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 org.wpilib.hardware.hal;
006
007import org.wpilib.hardware.hal.struct.ControlWordStruct;
008
009/** A wrapper for the HALControlWord bitfield. */
010public class ControlWord {
011  private static final long OPMODE_HASH_MASK = 0x00FFFFFFFFFFFFFFL;
012  private static final long ROBOT_MODE_MASK = 0x0300000000000000L;
013  private static final long ROBOT_MODE_SHIFT = 56;
014  private static final long ENABLED_MASK = 0x0400000000000000L;
015  private static final long ESTOP_MASK = 0x0800000000000000L;
016  private static final long FMS_ATTACHED_MASK = 0x1000000000000000L;
017  private static final long DS_ATTACHED_MASK = 0x2000000000000000L;
018
019  private long m_word;
020  private RobotMode m_robotMode = RobotMode.UNKNOWN;
021
022  /** Default constructor. */
023  public ControlWord() {}
024
025  /**
026   * Updates from state values.
027   *
028   * @param opModeHash opmode hash
029   * @param robotMode robot mode
030   * @param enabled enabled
031   * @param emergencyStop emergency stopped
032   * @param fmsAttached FMS attached
033   * @param dsAttached DS attached
034   */
035  public void update(
036      long opModeHash,
037      RobotMode robotMode,
038      boolean enabled,
039      boolean emergencyStop,
040      boolean fmsAttached,
041      boolean dsAttached) {
042    m_word =
043        (opModeHash & OPMODE_HASH_MASK)
044            | ((long) robotMode.getValue() << ROBOT_MODE_SHIFT)
045            | (enabled ? ENABLED_MASK : 0)
046            | (emergencyStop ? ESTOP_MASK : 0)
047            | (fmsAttached ? FMS_ATTACHED_MASK : 0)
048            | (dsAttached ? DS_ATTACHED_MASK : 0);
049    m_robotMode = robotMode;
050  }
051
052  /**
053   * Updates from the native HAL value.
054   *
055   * @param word value
056   */
057  public void update(long word) {
058    m_word = word;
059    m_robotMode = RobotMode.fromInt((int) ((word & ROBOT_MODE_MASK) >> ROBOT_MODE_SHIFT));
060  }
061
062  /**
063   * Updates from an existing word.
064   *
065   * @param word word to update from
066   */
067  public void update(ControlWord word) {
068    m_word = word.m_word;
069    m_robotMode = word.m_robotMode;
070  }
071
072  /**
073   * Gets the opmode ID.
074   *
075   * @return the opmode ID
076   */
077  public long getOpModeId() {
078    // if the hash portion is zero, return 0
079    if ((m_word & OPMODE_HASH_MASK) == 0) {
080      return 0;
081    }
082    // otherwise return the full ID (which includes the robot mode)
083    return m_word & (OPMODE_HASH_MASK | ROBOT_MODE_MASK);
084  }
085
086  /**
087   * Sets the opmode ID.
088   *
089   * @param id opmode ID
090   */
091  public void setOpModeId(long id) {
092    m_word &= ~(OPMODE_HASH_MASK | ROBOT_MODE_MASK);
093    m_word |= id & (OPMODE_HASH_MASK | ROBOT_MODE_MASK);
094    // keep robot mode in sync
095    m_robotMode = RobotMode.fromInt((int) ((m_word & ROBOT_MODE_MASK) >> ROBOT_MODE_SHIFT));
096  }
097
098  /**
099   * Gets the robot mode.
100   *
101   * @return the robot mode
102   */
103  public RobotMode getRobotMode() {
104    return m_robotMode;
105  }
106
107  /**
108   * Gets the Enabled flag.
109   *
110   * @return the Enabled flag
111   */
112  public boolean isEnabled() {
113    return (m_word & ENABLED_MASK) != 0;
114  }
115
116  /**
117   * Gets the E-Stop flag.
118   *
119   * @return the E-Stop flag
120   */
121  public boolean isEStopped() {
122    return (m_word & ESTOP_MASK) != 0;
123  }
124
125  /**
126   * Gets the FMS attached flag.
127   *
128   * @return the FMS attached flag
129   */
130  public boolean isFMSAttached() {
131    return (m_word & FMS_ATTACHED_MASK) != 0;
132  }
133
134  /**
135   * Gets the DS attached flag.
136   *
137   * @return the DS attached flag
138   */
139  public boolean isDSAttached() {
140    return (m_word & DS_ATTACHED_MASK) != 0;
141  }
142
143  /**
144   * Gets a value indicating whether the Driver Station requires the robot to be running in
145   * autonomous mode.
146   *
147   * @return True if autonomous mode should be enabled, false otherwise.
148   */
149  public boolean isAutonomous() {
150    return getRobotMode() == RobotMode.AUTONOMOUS;
151  }
152
153  /**
154   * Gets a value indicating whether the Driver Station requires the robot to be running in
155   * autonomous mode and enabled.
156   *
157   * @return True if autonomous should be set and the robot should be enabled.
158   */
159  public boolean isAutonomousEnabled() {
160    return isAutonomous() && isEnabled() && isDSAttached();
161  }
162
163  /**
164   * Gets a value indicating whether the Driver Station requires the robot to be running in
165   * operator-controlled mode.
166   *
167   * @return True if operator-controlled mode should be enabled, false otherwise.
168   */
169  public boolean isTeleop() {
170    return getRobotMode() == RobotMode.TELEOPERATED;
171  }
172
173  /**
174   * Gets a value indicating whether the Driver Station requires the robot to be running in
175   * operator-controller mode and enabled.
176   *
177   * @return True if operator-controlled mode should be set and the robot should be enabled.
178   */
179  public boolean isTeleopEnabled() {
180    return isTeleop() && isEnabled() && isDSAttached();
181  }
182
183  /**
184   * Gets a value indicating whether the Driver Station requires the robot to be running in test
185   * mode.
186   *
187   * @return True if test mode should be enabled, false otherwise.
188   */
189  public boolean isTest() {
190    return getRobotMode() == RobotMode.TEST;
191  }
192
193  /**
194   * Gets a value indicating whether the Driver Station requires the robot to be running in test
195   * mode and enabled.
196   *
197   * @return True if test mode should be set and the robot should be enabled.
198   */
199  public boolean isTestEnabled() {
200    return isTest() && isEnabled() && isDSAttached();
201  }
202
203  /**
204   * Gets the native HAL control word value.
205   *
206   * @return control word value
207   */
208  public long getNative() {
209    return m_word;
210  }
211
212  @Override
213  public boolean equals(Object obj) {
214    return obj instanceof ControlWord word && m_word == word.m_word;
215  }
216
217  @Override
218  public int hashCode() {
219    return Long.hashCode(m_word);
220  }
221
222  public static final ControlWordStruct struct = new ControlWordStruct();
223}