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.FRCNetComm.tResourceType;
009import edu.wpi.first.hal.HAL;
010import edu.wpi.first.hal.PWMJNI;
011
012/**
013 * A class for driving addressable LEDs, such as WS2812B, WS2815, and NeoPixels.
014 *
015 * <p>By default, the timing supports WS2812B and WS2815 LEDs, but is configurable using {@link
016 * #setBitTiming(int, int, int, int)}
017 *
018 * <p>Some LEDs use a different color order than the default GRB. The color order is configurable
019 * using {@link #setColorOrder(ColorOrder)}.
020 *
021 * <p>Only 1 LED driver is currently supported by the roboRIO. However, multiple LED strips can be
022 * connected in series and controlled from the single driver.
023 */
024public class AddressableLED implements AutoCloseable {
025  /** Order that color data is sent over the wire. */
026  public enum ColorOrder {
027    /** RGB order. */
028    kRGB(AddressableLEDJNI.COLOR_ORDER_RGB),
029    /** RBG order. */
030    kRBG(AddressableLEDJNI.COLOR_ORDER_RBG),
031    /** BGR order. */
032    kBGR(AddressableLEDJNI.COLOR_ORDER_BGR),
033    /** BRG order. */
034    kBRG(AddressableLEDJNI.COLOR_ORDER_BRG),
035    /** GBR order. */
036    kGBR(AddressableLEDJNI.COLOR_ORDER_GBR),
037    /** GRB order. This is the default order. */
038    kGRB(AddressableLEDJNI.COLOR_ORDER_GRB);
039
040    /** The native value for this ColorOrder. */
041    public final int value;
042
043    ColorOrder(int value) {
044      this.value = value;
045    }
046
047    /**
048     * Gets a color order from an int value.
049     *
050     * @param value int value
051     * @return color order
052     */
053    public ColorOrder fromValue(int value) {
054      return switch (value) {
055        case AddressableLEDJNI.COLOR_ORDER_RBG -> kRBG;
056        case AddressableLEDJNI.COLOR_ORDER_BGR -> kBGR;
057        case AddressableLEDJNI.COLOR_ORDER_BRG -> kBRG;
058        case AddressableLEDJNI.COLOR_ORDER_GRB -> kGRB;
059        case AddressableLEDJNI.COLOR_ORDER_GBR -> kGBR;
060        case AddressableLEDJNI.COLOR_ORDER_RGB -> kRGB;
061        default -> kGRB;
062      };
063    }
064  }
065
066  private final int m_pwmHandle;
067  private final int m_handle;
068
069  /**
070   * Constructs a new driver for a specific port.
071   *
072   * @param port the output port to use (Must be a PWM header, not on MXP)
073   */
074  public AddressableLED(int port) {
075    m_pwmHandle = PWMJNI.initializePWMPort(HAL.getPort((byte) port));
076    m_handle = AddressableLEDJNI.initialize(m_pwmHandle);
077    HAL.report(tResourceType.kResourceType_AddressableLEDs, port + 1);
078  }
079
080  @Override
081  public void close() {
082    if (m_handle != 0) {
083      AddressableLEDJNI.free(m_handle);
084    }
085    if (m_pwmHandle != 0) {
086      PWMJNI.freePWMPort(m_pwmHandle);
087    }
088  }
089
090  /**
091   * Sets the color order for this AddressableLED. The default order is GRB.
092   *
093   * <p>This will take effect on the next call to {@link #setData(AddressableLEDBuffer)}.
094   *
095   * @param order the color order
096   */
097  public void setColorOrder(ColorOrder order) {
098    AddressableLEDJNI.setColorOrder(m_handle, order.value);
099  }
100
101  /**
102   * Sets the length of the LED strip.
103   *
104   * <p>Calling this is an expensive call, so it's best to call it once, then just update data.
105   *
106   * <p>The max length is 5460 LEDs.
107   *
108   * @param length the strip length
109   */
110  public void setLength(int length) {
111    AddressableLEDJNI.setLength(m_handle, length);
112  }
113
114  /**
115   * Sets the LED output data.
116   *
117   * <p>If the output is enabled, this will start writing the next data cycle. It is safe to call,
118   * even while output is enabled.
119   *
120   * @param buffer the buffer to write
121   */
122  public void setData(AddressableLEDBuffer buffer) {
123    AddressableLEDJNI.setData(m_handle, buffer.m_buffer);
124  }
125
126  /**
127   * Sets the bit timing.
128   *
129   * <p>By default, the driver is set up to drive WS2812B and WS2815, so nothing needs to be set for
130   * those.
131   *
132   * @param highTime0NanoSeconds high time for 0 bit (default 400ns)
133   * @param lowTime0NanoSeconds low time for 0 bit (default 900ns)
134   * @param highTime1NanoSeconds high time for 1 bit (default 900ns)
135   * @param lowTime1NanoSeconds low time for 1 bit (default 600ns)
136   */
137  public void setBitTiming(
138      int highTime0NanoSeconds,
139      int lowTime0NanoSeconds,
140      int highTime1NanoSeconds,
141      int lowTime1NanoSeconds) {
142    AddressableLEDJNI.setBitTiming(
143        m_handle,
144        highTime0NanoSeconds,
145        lowTime0NanoSeconds,
146        highTime1NanoSeconds,
147        lowTime1NanoSeconds);
148  }
149
150  /**
151   * Sets the sync time.
152   *
153   * <p>The sync time is the time to hold output so LEDs enable. Default set for WS2812B and WS2815.
154   *
155   * @param syncTimeMicroSeconds the sync time (default 280us)
156   */
157  public void setSyncTime(int syncTimeMicroSeconds) {
158    AddressableLEDJNI.setSyncTime(m_handle, syncTimeMicroSeconds);
159  }
160
161  /**
162   * Starts the output.
163   *
164   * <p>The output writes continuously.
165   */
166  public void start() {
167    AddressableLEDJNI.start(m_handle);
168  }
169
170  /** Stops the output. */
171  public void stop() {
172    AddressableLEDJNI.stop(m_handle);
173  }
174}