001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj;
006
007import edu.wpi.first.hal.AddressableLEDJNI;
008import edu.wpi.first.hal.HAL;
009
010/**
011 * A class for driving addressable LEDs, such as WS2812B, WS2815, and NeoPixels.
012 *
013 * <p>Some LEDs use a different color order than the default GRB. The color order is configurable
014 * using {@link #setColorOrder(ColorOrder)}.
015 *
016 * <p>Up to 1024 LEDs may be controlled in total across all AddressableLED instances. A single
017 * global buffer is used for all instances. The start position used for LED data for the output is
018 * set via SetStart() and the length of the strip is set via SetLength(). Both of these default to
019 * zero, so multiple instances will access the same pixel data unless SetStart() is called to adjust
020 * the starting point.
021 */
022public class AddressableLED implements AutoCloseable {
023  /** Order that color data is sent over the wire. */
024  public enum ColorOrder {
025    /** RGB order. */
026    kRGB(AddressableLEDJNI.COLOR_ORDER_RGB),
027    /** RBG order. */
028    kRBG(AddressableLEDJNI.COLOR_ORDER_RBG),
029    /** BGR order. */
030    kBGR(AddressableLEDJNI.COLOR_ORDER_BGR),
031    /** BRG order. */
032    kBRG(AddressableLEDJNI.COLOR_ORDER_BRG),
033    /** GBR order. */
034    kGBR(AddressableLEDJNI.COLOR_ORDER_GBR),
035    /** GRB order. This is the default order. */
036    kGRB(AddressableLEDJNI.COLOR_ORDER_GRB);
037
038    /** The native value for this ColorOrder. */
039    public final int value;
040
041    ColorOrder(int value) {
042      this.value = value;
043    }
044
045    /**
046     * Gets a color order from an int value.
047     *
048     * @param value int value
049     * @return color order
050     */
051    public ColorOrder fromValue(int value) {
052      return switch (value) {
053        case AddressableLEDJNI.COLOR_ORDER_RBG -> kRBG;
054        case AddressableLEDJNI.COLOR_ORDER_BGR -> kBGR;
055        case AddressableLEDJNI.COLOR_ORDER_BRG -> kBRG;
056        case AddressableLEDJNI.COLOR_ORDER_GRB -> kGRB;
057        case AddressableLEDJNI.COLOR_ORDER_GBR -> kGBR;
058        case AddressableLEDJNI.COLOR_ORDER_RGB -> kRGB;
059        default -> kGRB;
060      };
061    }
062  }
063
064  private final int m_channel;
065  private final int m_handle;
066  private int m_start;
067  private int m_length;
068  private ColorOrder m_colorOrder = ColorOrder.kGRB;
069
070  /**
071   * Constructs a new driver for a specific channel.
072   *
073   * @param channel the output channel to use
074   */
075  public AddressableLED(int channel) {
076    m_channel = channel;
077    m_handle = AddressableLEDJNI.initialize(channel);
078    HAL.reportUsage("IO", channel, "AddressableLED");
079  }
080
081  @Override
082  public void close() {
083    if (m_handle != 0) {
084      AddressableLEDJNI.free(m_handle);
085    }
086  }
087
088  /**
089   * Gets the output channel.
090   *
091   * @return the output channel
092   */
093  public int getChannel() {
094    return m_channel;
095  }
096
097  /**
098   * Sets the color order for this AddressableLED. The default order is GRB.
099   *
100   * <p>This will take effect on the next call to {@link #setData(AddressableLEDBuffer)}.
101   *
102   * @param order the color order
103   */
104  public void setColorOrder(ColorOrder order) {
105    m_colorOrder = order;
106  }
107
108  /**
109   * Sets the display start of the LED strip in the global buffer.
110   *
111   * @param start the strip start, in LEDs
112   */
113  public void setStart(int start) {
114    m_start = start;
115    AddressableLEDJNI.setStart(m_handle, start);
116  }
117
118  /**
119   * Gets the display start of the LED strip in the global buffer.
120   *
121   * @return the strip start, in LEDs
122   */
123  public int getStart() {
124    return m_start;
125  }
126
127  /**
128   * Sets the length of the LED strip.
129   *
130   * @param length the strip length, in LEDs
131   */
132  public void setLength(int length) {
133    m_length = length;
134    AddressableLEDJNI.setLength(m_handle, length);
135  }
136
137  /**
138   * Sets the LED output data.
139   *
140   * <p>This will write to the global buffer starting at the location set by setStart() and up to
141   * the length set by setLength().
142   *
143   * @param buffer the buffer to write
144   */
145  public void setData(AddressableLEDBuffer buffer) {
146    AddressableLEDJNI.setData(
147        m_start,
148        m_colorOrder.value,
149        buffer.m_buffer,
150        0,
151        3 * Math.min(m_length, buffer.getLength()));
152  }
153
154  /**
155   * Sets the LED output data at an arbitrary location in the global buffer.
156   *
157   * @param start the start location, in LEDs
158   * @param colorOrder the color order
159   * @param buffer the buffer to write
160   */
161  public static void setGlobalData(int start, ColorOrder colorOrder, AddressableLEDBuffer buffer) {
162    AddressableLEDJNI.setData(start, colorOrder.value, buffer.m_buffer);
163  }
164}