001/*
002 * Copyright (C) Cross The Road Electronics.  All rights reserved.
003 * License information can be found in CTRE_LICENSE.txt
004 * For support and suggestions contact support@ctr-electronics.com or file
005 * an issue tracker at https://github.com/CrossTheRoadElec/Phoenix-Releases
006 */
007package com.ctre.phoenix6.controls;
008
009import com.ctre.phoenix6.StatusCode;
010import com.ctre.phoenix6.controls.jni.ControlJNI;
011import com.ctre.phoenix6.hardware.traits.*;
012
013import edu.wpi.first.units.*;
014import edu.wpi.first.units.measure.*;
015import static edu.wpi.first.units.Units.*;
016
017import java.util.HashMap;
018import java.util.Map;
019
020/**
021 * Request a specified motor duty cycle.
022 * <p>
023 * This control mode will output a proportion of the supplied voltage which is supplied by the user.
024 */
025public class DutyCycleOut extends ControlRequest implements Cloneable
026{
027    /**
028     * Proportion of supply voltage to apply in fractional units between -1 and +1
029     * 
030     * <ul>
031     *   <li> Units: fractional
032     * </ul>
033     * 
034     */
035    public double Output;
036    /**
037     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
038     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
039     * false to use trapezoidal commutation.
040     * <p>
041     * FOC improves motor performance by leveraging torque (current) control. 
042     * However, this may be inconvenient for applications that require specifying
043     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
044     * combines the performances gains of FOC while still allowing applications to
045     * provide duty cycle or voltage demand.  This not to be confused with simple
046     * sinusoidal control or phase voltage control which lacks the performance
047     * gains.
048     */
049    public boolean EnableFOC = true;
050    /**
051     * Set to true to static-brake the rotor when output is zero (or within
052     * deadband).  Set to false to use the NeutralMode configuration setting
053     * (default). This flag exists to provide the fundamental behavior of this
054     * control when output is zero, which is to provide 0V to the motor.
055     */
056    public boolean OverrideBrakeDurNeutral = false;
057    /**
058     * Set to true to force forward limiting.  This allows users to use other limit
059     * switch sensors connected to robot controller.  This also allows use of active
060     * sensors that require external power.
061     */
062    public boolean LimitForwardMotion = false;
063    /**
064     * Set to true to force reverse limiting.  This allows users to use other limit
065     * switch sensors connected to robot controller.  This also allows use of active
066     * sensors that require external power.
067     */
068    public boolean LimitReverseMotion = false;
069    /**
070     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
071     * LimitReverseMotion parameters, instead allowing motion.
072     * <p>
073     * This can be useful on mechanisms such as an intake/feeder, where a limit
074     * switch stops motion while intaking but should be ignored when feeding to a
075     * shooter.
076     * <p>
077     * The hardware limit faults and Forward/ReverseLimit signals will still report
078     * the values of the limit switches regardless of this parameter.
079     */
080    public boolean IgnoreHardwareLimits = false;
081    /**
082     * Set to true to delay applying this control request until a timesync boundary
083     * (requires Phoenix Pro and CANivore). This eliminates the impact of
084     * nondeterministic network delays in exchange for a larger but deterministic
085     * control latency.
086     * <p>
087     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
088     * Additionally, when this is enabled, the UpdateFreqHz of this request should
089     * be set to 0 Hz.
090     */
091    public boolean UseTimesync = false;
092
093    /**
094     * The period at which this control will update at.
095     * This is designated in Hertz, with a minimum of 20 Hz
096     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
097     * <p>
098     * If this field is set to 0 Hz, the control request will
099     * be sent immediately as a one-shot frame. This may be useful
100     * for advanced applications that require outputs to be
101     * synchronized with data acquisition. In this case, we
102     * recommend not exceeding 50 ms between control calls.
103     */
104    public double UpdateFreqHz = 100;
105
106    /**
107     * Request a specified motor duty cycle.
108     * <p>
109     * This control mode will output a proportion of the supplied voltage which is
110     * supplied by the user.
111     * 
112     * @param Output    Proportion of supply voltage to apply in fractional units
113     *                  between -1 and +1
114     */
115    public DutyCycleOut(double Output)
116    {
117        super("DutyCycleOut");
118        this.Output = Output;
119    }
120
121    @Override
122    public String toString()
123    {
124        String ss = "Control: DutyCycleOut\n";
125        ss += "    Output: " + Output + " fractional" + "\n";
126        ss += "    EnableFOC: " + EnableFOC + "\n";
127        ss += "    OverrideBrakeDurNeutral: " + OverrideBrakeDurNeutral + "\n";
128        ss += "    LimitForwardMotion: " + LimitForwardMotion + "\n";
129        ss += "    LimitReverseMotion: " + LimitReverseMotion + "\n";
130        ss += "    IgnoreHardwareLimits: " + IgnoreHardwareLimits + "\n";
131        ss += "    UseTimesync: " + UseTimesync + "\n";
132        return ss;
133    }
134
135    @Override
136    public StatusCode sendRequest(String network, int deviceHash)
137    {
138        return StatusCode.valueOf(ControlJNI.JNI_RequestControlDutyCycleOut(
139                network, deviceHash, UpdateFreqHz, Output, EnableFOC, OverrideBrakeDurNeutral, LimitForwardMotion, LimitReverseMotion, IgnoreHardwareLimits, UseTimesync));
140    }
141
142    /**
143     * Gets information about this control request.
144     *
145     * @return Map of control parameter names and corresponding applied values
146     */
147    @Override
148    public Map<String, String> getControlInfo()
149    {
150        var controlInfo = new HashMap<String, String>();
151        controlInfo.put("Name", getName());
152        controlInfo.put("Output", String.valueOf(this.Output));
153        controlInfo.put("EnableFOC", String.valueOf(this.EnableFOC));
154        controlInfo.put("OverrideBrakeDurNeutral", String.valueOf(this.OverrideBrakeDurNeutral));
155        controlInfo.put("LimitForwardMotion", String.valueOf(this.LimitForwardMotion));
156        controlInfo.put("LimitReverseMotion", String.valueOf(this.LimitReverseMotion));
157        controlInfo.put("IgnoreHardwareLimits", String.valueOf(this.IgnoreHardwareLimits));
158        controlInfo.put("UseTimesync", String.valueOf(this.UseTimesync));
159        return controlInfo;
160    }
161    
162    /**
163     * Modifies this Control Request's Output parameter and returns itself for
164     * method-chaining and easier to use request API.
165     * <p>
166     * Proportion of supply voltage to apply in fractional units between -1 and +1
167     * 
168     * <ul>
169     *   <li> Units: fractional
170     * </ul>
171     * 
172     *
173     * @param newOutput Parameter to modify
174     * @return Itself
175     */
176    public DutyCycleOut withOutput(double newOutput)
177    {
178        Output = newOutput;
179        return this;
180    }
181    
182    /**
183     * Modifies this Control Request's EnableFOC parameter and returns itself for
184     * method-chaining and easier to use request API.
185     * <p>
186     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
187     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
188     * false to use trapezoidal commutation.
189     * <p>
190     * FOC improves motor performance by leveraging torque (current) control. 
191     * However, this may be inconvenient for applications that require specifying
192     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
193     * combines the performances gains of FOC while still allowing applications to
194     * provide duty cycle or voltage demand.  This not to be confused with simple
195     * sinusoidal control or phase voltage control which lacks the performance
196     * gains.
197     *
198     * @param newEnableFOC Parameter to modify
199     * @return Itself
200     */
201    public DutyCycleOut withEnableFOC(boolean newEnableFOC)
202    {
203        EnableFOC = newEnableFOC;
204        return this;
205    }
206    
207    /**
208     * Modifies this Control Request's OverrideBrakeDurNeutral parameter and returns itself for
209     * method-chaining and easier to use request API.
210     * <p>
211     * Set to true to static-brake the rotor when output is zero (or within
212     * deadband).  Set to false to use the NeutralMode configuration setting
213     * (default). This flag exists to provide the fundamental behavior of this
214     * control when output is zero, which is to provide 0V to the motor.
215     *
216     * @param newOverrideBrakeDurNeutral Parameter to modify
217     * @return Itself
218     */
219    public DutyCycleOut withOverrideBrakeDurNeutral(boolean newOverrideBrakeDurNeutral)
220    {
221        OverrideBrakeDurNeutral = newOverrideBrakeDurNeutral;
222        return this;
223    }
224    
225    /**
226     * Modifies this Control Request's LimitForwardMotion parameter and returns itself for
227     * method-chaining and easier to use request API.
228     * <p>
229     * Set to true to force forward limiting.  This allows users to use other limit
230     * switch sensors connected to robot controller.  This also allows use of active
231     * sensors that require external power.
232     *
233     * @param newLimitForwardMotion Parameter to modify
234     * @return Itself
235     */
236    public DutyCycleOut withLimitForwardMotion(boolean newLimitForwardMotion)
237    {
238        LimitForwardMotion = newLimitForwardMotion;
239        return this;
240    }
241    
242    /**
243     * Modifies this Control Request's LimitReverseMotion parameter and returns itself for
244     * method-chaining and easier to use request API.
245     * <p>
246     * Set to true to force reverse limiting.  This allows users to use other limit
247     * switch sensors connected to robot controller.  This also allows use of active
248     * sensors that require external power.
249     *
250     * @param newLimitReverseMotion Parameter to modify
251     * @return Itself
252     */
253    public DutyCycleOut withLimitReverseMotion(boolean newLimitReverseMotion)
254    {
255        LimitReverseMotion = newLimitReverseMotion;
256        return this;
257    }
258    
259    /**
260     * Modifies this Control Request's IgnoreHardwareLimits parameter and returns itself for
261     * method-chaining and easier to use request API.
262     * <p>
263     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
264     * LimitReverseMotion parameters, instead allowing motion.
265     * <p>
266     * This can be useful on mechanisms such as an intake/feeder, where a limit
267     * switch stops motion while intaking but should be ignored when feeding to a
268     * shooter.
269     * <p>
270     * The hardware limit faults and Forward/ReverseLimit signals will still report
271     * the values of the limit switches regardless of this parameter.
272     *
273     * @param newIgnoreHardwareLimits Parameter to modify
274     * @return Itself
275     */
276    public DutyCycleOut withIgnoreHardwareLimits(boolean newIgnoreHardwareLimits)
277    {
278        IgnoreHardwareLimits = newIgnoreHardwareLimits;
279        return this;
280    }
281    
282    /**
283     * Modifies this Control Request's UseTimesync parameter and returns itself for
284     * method-chaining and easier to use request API.
285     * <p>
286     * Set to true to delay applying this control request until a timesync boundary
287     * (requires Phoenix Pro and CANivore). This eliminates the impact of
288     * nondeterministic network delays in exchange for a larger but deterministic
289     * control latency.
290     * <p>
291     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
292     * Additionally, when this is enabled, the UpdateFreqHz of this request should
293     * be set to 0 Hz.
294     *
295     * @param newUseTimesync Parameter to modify
296     * @return Itself
297     */
298    public DutyCycleOut withUseTimesync(boolean newUseTimesync)
299    {
300        UseTimesync = newUseTimesync;
301        return this;
302    }
303
304    /**
305     * Sets the period at which this control will update at.
306     * This is designated in Hertz, with a minimum of 20 Hz
307     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
308     * <p>
309     * If this field is set to 0 Hz, the control request will
310     * be sent immediately as a one-shot frame. This may be useful
311     * for advanced applications that require outputs to be
312     * synchronized with data acquisition. In this case, we
313     * recommend not exceeding 50 ms between control calls.
314     *
315     * @param newUpdateFreqHz Parameter to modify
316     * @return Itself
317     */
318    @Override
319    public DutyCycleOut withUpdateFreqHz(double newUpdateFreqHz)
320    {
321        UpdateFreqHz = newUpdateFreqHz;
322        return this;
323    }
324
325    /**
326     * Sets the period at which this control will update at.
327     * This is designated in Hertz, with a minimum of 20 Hz
328     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
329     * <p>
330     * If this field is set to 0 Hz, the control request will
331     * be sent immediately as a one-shot frame. This may be useful
332     * for advanced applications that require outputs to be
333     * synchronized with data acquisition. In this case, we
334     * recommend not exceeding 50 ms between control calls.
335     *
336     * @param newUpdateFreqHz Parameter to modify
337     * @return Itself
338     */
339    @Override
340    public DutyCycleOut withUpdateFreqHz(Frequency newUpdateFreqHz)
341    {
342        UpdateFreqHz = newUpdateFreqHz.in(Hertz);
343        return this;
344    }
345
346    @Override
347    public DutyCycleOut clone()
348    {
349        try {
350            return (DutyCycleOut)super.clone();
351        } catch (CloneNotSupportedException ex) {
352            /* this should never happen */
353            throw new RuntimeException(ex);
354        }
355    }
356}
357