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 * Requires Phoenix Pro and CANivore;
022 * Requests Motion Magic® to target a final position using a motion profile. 
023 * This dynamic request allows runtime changes to Cruise Velocity, Acceleration,
024 * and (optional) Jerk.  Users can optionally provide a duty cycle feedforward.
025 * <p>
026 * Motion Magic® produces a motion profile in real-time while attempting to honor the specified Cruise
027 * Velocity, Acceleration, and (optional) Jerk.  This control mode does not use the Expo_kV or Expo_kA
028 * configs.
029 * <p>
030 * Target position can be changed on-the-fly and Motion Magic® will do its best to adjust the profile. This
031 * control mode is duty cycle based, so relevant closed-loop gains will use fractional duty cycle for the
032 * numerator:  +1.0 represents full forward output.
033 */
034public final class DynamicMotionMagicDutyCycle implements ControlRequest, Cloneable {
035    /**
036     * Position to drive toward in rotations.
037     * 
038     * <ul>
039     *   <li> Units: rotations
040     * </ul>
041     * 
042     */
043    public double Position;
044    /**
045     * Cruise velocity for profiling.  The signage does not matter as the device
046     * will use the absolute value for profile generation.
047     * 
048     * <ul>
049     *   <li> Units: rotations per second
050     * </ul>
051     * 
052     */
053    public double Velocity;
054    /**
055     * Acceleration for profiling.  The signage does not matter as the device will
056     * use the absolute value for profile generation
057     * 
058     * <ul>
059     *   <li> Units: rotations per second²
060     * </ul>
061     * 
062     */
063    public double Acceleration;
064    /**
065     * Jerk for profiling.  The signage does not matter as the device will use the
066     * absolute value for profile generation.
067     * <p>
068     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
069     * Jerk limit.
070     * 
071     * <ul>
072     *   <li> Units: rotations per second³
073     * </ul>
074     * 
075     */
076    public double Jerk = 0.0;
077    /**
078     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
079     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
080     * false to use trapezoidal commutation.
081     * <p>
082     * FOC improves motor performance by leveraging torque (current) control. 
083     * However, this may be inconvenient for applications that require specifying
084     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
085     * combines the performances gains of FOC while still allowing applications to
086     * provide duty cycle or voltage demand.  This not to be confused with simple
087     * sinusoidal control or phase voltage control which lacks the performance
088     * gains.
089     */
090    public boolean EnableFOC = true;
091    /**
092     * Feedforward to apply in fractional units between -1 and +1. This is added to
093     * the output of the onboard feedforward terms.
094     * 
095     * <ul>
096     *   <li> Units: fractional
097     * </ul>
098     * 
099     */
100    public double FeedForward = 0.0;
101    /**
102     * Select which gains are applied by selecting the slot.  Use the configuration
103     * api to set the gain values for the selected slot before enabling this
104     * feature. Slot must be within [0,2].
105     */
106    public int Slot = 0;
107    /**
108     * Set to true to static-brake the rotor when output is zero (or within
109     * deadband).  Set to false to use the NeutralMode configuration setting
110     * (default). This flag exists to provide the fundamental behavior of this
111     * control when output is zero, which is to provide 0V to the motor.
112     */
113    public boolean OverrideBrakeDurNeutral = false;
114    /**
115     * Set to true to force forward limiting.  This allows users to use other limit
116     * switch sensors connected to robot controller.  This also allows use of active
117     * sensors that require external power.
118     */
119    public boolean LimitForwardMotion = false;
120    /**
121     * Set to true to force reverse limiting.  This allows users to use other limit
122     * switch sensors connected to robot controller.  This also allows use of active
123     * sensors that require external power.
124     */
125    public boolean LimitReverseMotion = false;
126    /**
127     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
128     * LimitReverseMotion parameters, instead allowing motion.
129     * <p>
130     * This can be useful on mechanisms such as an intake/feeder, where a limit
131     * switch stops motion while intaking but should be ignored when feeding to a
132     * shooter.
133     * <p>
134     * The hardware limit faults and Forward/ReverseLimit signals will still report
135     * the values of the limit switches regardless of this parameter.
136     */
137    public boolean IgnoreHardwareLimits = false;
138    /**
139     * Set to true to ignore software limits, instead allowing motion.
140     * <p>
141     * This can be useful when calibrating the zero point of a mechanism such as an
142     * elevator.
143     * <p>
144     * The software limit faults will still report the values of the software limits
145     * regardless of this parameter.
146     */
147    public boolean IgnoreSoftwareLimits = false;
148    /**
149     * Set to true to delay applying this control request until a timesync boundary
150     * (requires Phoenix Pro and CANivore). This eliminates the impact of
151     * nondeterministic network delays in exchange for a larger but deterministic
152     * control latency.
153     * <p>
154     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
155     * Additionally, when this is enabled, the UpdateFreqHz of this request should
156     * be set to 0 Hz.
157     */
158    public boolean UseTimesync = false;
159
160    /**
161     * The frequency at which this control will update.
162     * This is designated in Hertz, with a minimum of 20 Hz
163     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
164     * Some update frequencies are not supported and will be
165     * promoted up to the next highest supported frequency.
166     * <p>
167     * If this field is set to 0 Hz, the control request will
168     * be sent immediately as a one-shot frame. This may be useful
169     * for advanced applications that require outputs to be
170     * synchronized with data acquisition. In this case, we
171     * recommend not exceeding 50 ms between control calls.
172     */
173    public double UpdateFreqHz = 100;
174
175    /**
176     * Requires Phoenix Pro and CANivore;
177     * Requests Motion Magic® to target a final position using a motion profile. 
178     * This dynamic request allows runtime changes to Cruise Velocity, Acceleration,
179     * and (optional) Jerk.  Users can optionally provide a duty cycle feedforward.
180     * <p>
181     * Motion Magic® produces a motion profile in real-time while attempting to
182     * honor the specified Cruise Velocity, Acceleration, and (optional) Jerk.  This
183     * control mode does not use the Expo_kV or Expo_kA configs.
184     * <p>
185     * Target position can be changed on-the-fly and Motion Magic® will do its best
186     * to adjust the profile. This control mode is duty cycle based, so relevant
187     * closed-loop gains will use fractional duty cycle for the numerator:  +1.0
188     * represents full forward output.
189     * 
190     * @param Position Position to drive toward in rotations.
191     * @param Velocity Cruise velocity for profiling.  The signage does not matter
192     *                 as the device will use the absolute value for profile
193     *                 generation.
194     * @param Acceleration Acceleration for profiling.  The signage does not matter
195     *                     as the device will use the absolute value for profile
196     *                     generation
197     */
198    public DynamicMotionMagicDutyCycle(double Position, double Velocity, double Acceleration) {
199        this.Position = Position;
200        this.Velocity = Velocity;
201        this.Acceleration = Acceleration;
202    }
203
204    /**
205     * Requires Phoenix Pro and CANivore;
206     * Requests Motion Magic® to target a final position using a motion profile. 
207     * This dynamic request allows runtime changes to Cruise Velocity, Acceleration,
208     * and (optional) Jerk.  Users can optionally provide a duty cycle feedforward.
209     * <p>
210     * Motion Magic® produces a motion profile in real-time while attempting to
211     * honor the specified Cruise Velocity, Acceleration, and (optional) Jerk.  This
212     * control mode does not use the Expo_kV or Expo_kA configs.
213     * <p>
214     * Target position can be changed on-the-fly and Motion Magic® will do its best
215     * to adjust the profile. This control mode is duty cycle based, so relevant
216     * closed-loop gains will use fractional duty cycle for the numerator:  +1.0
217     * represents full forward output.
218     * 
219     * @param Position Position to drive toward in rotations.
220     * @param Velocity Cruise velocity for profiling.  The signage does not matter
221     *                 as the device will use the absolute value for profile
222     *                 generation.
223     * @param Acceleration Acceleration for profiling.  The signage does not matter
224     *                     as the device will use the absolute value for profile
225     *                     generation
226     */
227    public DynamicMotionMagicDutyCycle(Angle Position, AngularVelocity Velocity, AngularAcceleration Acceleration) {
228        this(Position.in(Rotations), Velocity.in(RotationsPerSecond), Acceleration.in(RotationsPerSecondPerSecond));
229    }
230
231    @Override
232    public String getName() {
233        return "DynamicMotionMagicDutyCycle";
234    }
235
236    @Override
237    public String toString() {
238        String ss = "Control: DynamicMotionMagicDutyCycle\n";
239        ss += "    Position: " + Position + " rotations" + "\n";
240        ss += "    Velocity: " + Velocity + " rotations per second" + "\n";
241        ss += "    Acceleration: " + Acceleration + " rotations per second²" + "\n";
242        ss += "    Jerk: " + Jerk + " rotations per second³" + "\n";
243        ss += "    EnableFOC: " + EnableFOC + "\n";
244        ss += "    FeedForward: " + FeedForward + " fractional" + "\n";
245        ss += "    Slot: " + Slot + "\n";
246        ss += "    OverrideBrakeDurNeutral: " + OverrideBrakeDurNeutral + "\n";
247        ss += "    LimitForwardMotion: " + LimitForwardMotion + "\n";
248        ss += "    LimitReverseMotion: " + LimitReverseMotion + "\n";
249        ss += "    IgnoreHardwareLimits: " + IgnoreHardwareLimits + "\n";
250        ss += "    IgnoreSoftwareLimits: " + IgnoreSoftwareLimits + "\n";
251        ss += "    UseTimesync: " + UseTimesync + "\n";
252        return ss;
253    }
254
255    @Override
256    public StatusCode sendRequest(String network, int deviceHash) {
257        return StatusCode.valueOf(ControlJNI.JNI_RequestControlDynamicMotionMagicDutyCycle(
258                network, deviceHash, UpdateFreqHz, Position, Velocity, Acceleration, Jerk, EnableFOC, FeedForward, Slot, OverrideBrakeDurNeutral, LimitForwardMotion, LimitReverseMotion, IgnoreHardwareLimits, IgnoreSoftwareLimits, UseTimesync));
259    }
260
261    /**
262     * Gets information about this control request.
263     *
264     * @return Map of control parameter names and corresponding applied values
265     */
266    @Override
267    public Map<String, String> getControlInfo() {
268        var controlInfo = new HashMap<String, String>();
269        controlInfo.put("Name", getName());
270        controlInfo.put("Position", String.valueOf(this.Position));
271        controlInfo.put("Velocity", String.valueOf(this.Velocity));
272        controlInfo.put("Acceleration", String.valueOf(this.Acceleration));
273        controlInfo.put("Jerk", String.valueOf(this.Jerk));
274        controlInfo.put("EnableFOC", String.valueOf(this.EnableFOC));
275        controlInfo.put("FeedForward", String.valueOf(this.FeedForward));
276        controlInfo.put("Slot", String.valueOf(this.Slot));
277        controlInfo.put("OverrideBrakeDurNeutral", String.valueOf(this.OverrideBrakeDurNeutral));
278        controlInfo.put("LimitForwardMotion", String.valueOf(this.LimitForwardMotion));
279        controlInfo.put("LimitReverseMotion", String.valueOf(this.LimitReverseMotion));
280        controlInfo.put("IgnoreHardwareLimits", String.valueOf(this.IgnoreHardwareLimits));
281        controlInfo.put("IgnoreSoftwareLimits", String.valueOf(this.IgnoreSoftwareLimits));
282        controlInfo.put("UseTimesync", String.valueOf(this.UseTimesync));
283        return controlInfo;
284    }
285    
286    /**
287     * Modifies this Control Request's Position parameter and returns itself for
288     * method-chaining and easier to use request API.
289     * <p>
290     * Position to drive toward in rotations.
291     * 
292     * <ul>
293     *   <li> Units: rotations
294     * </ul>
295     * 
296     *
297     * @param newPosition Parameter to modify
298     * @return Itself
299     */
300    public DynamicMotionMagicDutyCycle withPosition(double newPosition) {
301        Position = newPosition;
302        return this;
303    }
304    
305    /**
306     * Modifies this Control Request's Position parameter and returns itself for
307     * method-chaining and easier to use request API.
308     * <p>
309     * Position to drive toward in rotations.
310     * 
311     * <ul>
312     *   <li> Units: rotations
313     * </ul>
314     * 
315     *
316     * @param newPosition Parameter to modify
317     * @return Itself
318     */
319    public DynamicMotionMagicDutyCycle withPosition(Angle newPosition) {
320        Position = newPosition.in(Rotations);
321        return this;
322    }
323    
324    /**
325     * Helper method to get this Control Request's Position parameter converted
326     * to a unit type. If not using the Java units library, {@link #Position}
327     * can be accessed directly instead.
328     * <p>
329     * Position to drive toward in rotations.
330     * 
331     * <ul>
332     *   <li> Units: rotations
333     * </ul>
334     * 
335     *
336     * @return Position
337     */
338    public Angle getPositionMeasure() {
339        return Rotations.of(Position);
340    }
341    
342    /**
343     * Modifies this Control Request's Velocity parameter and returns itself for
344     * method-chaining and easier to use request API.
345     * <p>
346     * Cruise velocity for profiling.  The signage does not matter as the device
347     * will use the absolute value for profile generation.
348     * 
349     * <ul>
350     *   <li> Units: rotations per second
351     * </ul>
352     * 
353     *
354     * @param newVelocity Parameter to modify
355     * @return Itself
356     */
357    public DynamicMotionMagicDutyCycle withVelocity(double newVelocity) {
358        Velocity = newVelocity;
359        return this;
360    }
361    
362    /**
363     * Modifies this Control Request's Velocity parameter and returns itself for
364     * method-chaining and easier to use request API.
365     * <p>
366     * Cruise velocity for profiling.  The signage does not matter as the device
367     * will use the absolute value for profile generation.
368     * 
369     * <ul>
370     *   <li> Units: rotations per second
371     * </ul>
372     * 
373     *
374     * @param newVelocity Parameter to modify
375     * @return Itself
376     */
377    public DynamicMotionMagicDutyCycle withVelocity(AngularVelocity newVelocity) {
378        Velocity = newVelocity.in(RotationsPerSecond);
379        return this;
380    }
381    
382    /**
383     * Helper method to get this Control Request's Velocity parameter converted
384     * to a unit type. If not using the Java units library, {@link #Velocity}
385     * can be accessed directly instead.
386     * <p>
387     * Cruise velocity for profiling.  The signage does not matter as the device
388     * will use the absolute value for profile generation.
389     * 
390     * <ul>
391     *   <li> Units: rotations per second
392     * </ul>
393     * 
394     *
395     * @return Velocity
396     */
397    public AngularVelocity getVelocityMeasure() {
398        return RotationsPerSecond.of(Velocity);
399    }
400    
401    /**
402     * Modifies this Control Request's Acceleration parameter and returns itself for
403     * method-chaining and easier to use request API.
404     * <p>
405     * Acceleration for profiling.  The signage does not matter as the device will
406     * use the absolute value for profile generation
407     * 
408     * <ul>
409     *   <li> Units: rotations per second²
410     * </ul>
411     * 
412     *
413     * @param newAcceleration Parameter to modify
414     * @return Itself
415     */
416    public DynamicMotionMagicDutyCycle withAcceleration(double newAcceleration) {
417        Acceleration = newAcceleration;
418        return this;
419    }
420    
421    /**
422     * Modifies this Control Request's Acceleration parameter and returns itself for
423     * method-chaining and easier to use request API.
424     * <p>
425     * Acceleration for profiling.  The signage does not matter as the device will
426     * use the absolute value for profile generation
427     * 
428     * <ul>
429     *   <li> Units: rotations per second²
430     * </ul>
431     * 
432     *
433     * @param newAcceleration Parameter to modify
434     * @return Itself
435     */
436    public DynamicMotionMagicDutyCycle withAcceleration(AngularAcceleration newAcceleration) {
437        Acceleration = newAcceleration.in(RotationsPerSecondPerSecond);
438        return this;
439    }
440    
441    /**
442     * Helper method to get this Control Request's Acceleration parameter converted
443     * to a unit type. If not using the Java units library, {@link #Acceleration}
444     * can be accessed directly instead.
445     * <p>
446     * Acceleration for profiling.  The signage does not matter as the device will
447     * use the absolute value for profile generation
448     * 
449     * <ul>
450     *   <li> Units: rotations per second²
451     * </ul>
452     * 
453     *
454     * @return Acceleration
455     */
456    public AngularAcceleration getAccelerationMeasure() {
457        return RotationsPerSecondPerSecond.of(Acceleration);
458    }
459    
460    /**
461     * Modifies this Control Request's Jerk parameter and returns itself for
462     * method-chaining and easier to use request API.
463     * <p>
464     * Jerk for profiling.  The signage does not matter as the device will use the
465     * absolute value for profile generation.
466     * <p>
467     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
468     * Jerk limit.
469     * 
470     * <ul>
471     *   <li> Units: rotations per second³
472     * </ul>
473     * 
474     *
475     * @param newJerk Parameter to modify
476     * @return Itself
477     */
478    public DynamicMotionMagicDutyCycle withJerk(double newJerk) {
479        Jerk = newJerk;
480        return this;
481    }
482    
483    /**
484     * Modifies this Control Request's Jerk parameter and returns itself for
485     * method-chaining and easier to use request API.
486     * <p>
487     * Jerk for profiling.  The signage does not matter as the device will use the
488     * absolute value for profile generation.
489     * <p>
490     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
491     * Jerk limit.
492     * 
493     * <ul>
494     *   <li> Units: rotations per second³
495     * </ul>
496     * 
497     *
498     * @param newJerk Parameter to modify
499     * @return Itself
500     */
501    public DynamicMotionMagicDutyCycle withJerk(Velocity<AngularAccelerationUnit> newJerk) {
502        Jerk = newJerk.in(RotationsPerSecondPerSecond.per(Second));
503        return this;
504    }
505    
506    /**
507     * Helper method to get this Control Request's Jerk parameter converted
508     * to a unit type. If not using the Java units library, {@link #Jerk}
509     * can be accessed directly instead.
510     * <p>
511     * Jerk for profiling.  The signage does not matter as the device will use the
512     * absolute value for profile generation.
513     * <p>
514     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
515     * Jerk limit.
516     * 
517     * <ul>
518     *   <li> Units: rotations per second³
519     * </ul>
520     * 
521     *
522     * @return Jerk
523     */
524    public Velocity<AngularAccelerationUnit> getJerkMeasure() {
525        return RotationsPerSecondPerSecond.per(Second).of(Jerk);
526    }
527    
528    /**
529     * Modifies this Control Request's EnableFOC parameter and returns itself for
530     * method-chaining and easier to use request API.
531     * <p>
532     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
533     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
534     * false to use trapezoidal commutation.
535     * <p>
536     * FOC improves motor performance by leveraging torque (current) control. 
537     * However, this may be inconvenient for applications that require specifying
538     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
539     * combines the performances gains of FOC while still allowing applications to
540     * provide duty cycle or voltage demand.  This not to be confused with simple
541     * sinusoidal control or phase voltage control which lacks the performance
542     * gains.
543     *
544     * @param newEnableFOC Parameter to modify
545     * @return Itself
546     */
547    public DynamicMotionMagicDutyCycle withEnableFOC(boolean newEnableFOC) {
548        EnableFOC = newEnableFOC;
549        return this;
550    }
551    
552    /**
553     * Modifies this Control Request's FeedForward parameter and returns itself for
554     * method-chaining and easier to use request API.
555     * <p>
556     * Feedforward to apply in fractional units between -1 and +1. This is added to
557     * the output of the onboard feedforward terms.
558     * 
559     * <ul>
560     *   <li> Units: fractional
561     * </ul>
562     * 
563     *
564     * @param newFeedForward Parameter to modify
565     * @return Itself
566     */
567    public DynamicMotionMagicDutyCycle withFeedForward(double newFeedForward) {
568        FeedForward = newFeedForward;
569        return this;
570    }
571    
572    /**
573     * Modifies this Control Request's Slot parameter and returns itself for
574     * method-chaining and easier to use request API.
575     * <p>
576     * Select which gains are applied by selecting the slot.  Use the configuration
577     * api to set the gain values for the selected slot before enabling this
578     * feature. Slot must be within [0,2].
579     *
580     * @param newSlot Parameter to modify
581     * @return Itself
582     */
583    public DynamicMotionMagicDutyCycle withSlot(int newSlot) {
584        Slot = newSlot;
585        return this;
586    }
587    
588    /**
589     * Modifies this Control Request's OverrideBrakeDurNeutral parameter and returns itself for
590     * method-chaining and easier to use request API.
591     * <p>
592     * Set to true to static-brake the rotor when output is zero (or within
593     * deadband).  Set to false to use the NeutralMode configuration setting
594     * (default). This flag exists to provide the fundamental behavior of this
595     * control when output is zero, which is to provide 0V to the motor.
596     *
597     * @param newOverrideBrakeDurNeutral Parameter to modify
598     * @return Itself
599     */
600    public DynamicMotionMagicDutyCycle withOverrideBrakeDurNeutral(boolean newOverrideBrakeDurNeutral) {
601        OverrideBrakeDurNeutral = newOverrideBrakeDurNeutral;
602        return this;
603    }
604    
605    /**
606     * Modifies this Control Request's LimitForwardMotion parameter and returns itself for
607     * method-chaining and easier to use request API.
608     * <p>
609     * Set to true to force forward limiting.  This allows users to use other limit
610     * switch sensors connected to robot controller.  This also allows use of active
611     * sensors that require external power.
612     *
613     * @param newLimitForwardMotion Parameter to modify
614     * @return Itself
615     */
616    public DynamicMotionMagicDutyCycle withLimitForwardMotion(boolean newLimitForwardMotion) {
617        LimitForwardMotion = newLimitForwardMotion;
618        return this;
619    }
620    
621    /**
622     * Modifies this Control Request's LimitReverseMotion parameter and returns itself for
623     * method-chaining and easier to use request API.
624     * <p>
625     * Set to true to force reverse limiting.  This allows users to use other limit
626     * switch sensors connected to robot controller.  This also allows use of active
627     * sensors that require external power.
628     *
629     * @param newLimitReverseMotion Parameter to modify
630     * @return Itself
631     */
632    public DynamicMotionMagicDutyCycle withLimitReverseMotion(boolean newLimitReverseMotion) {
633        LimitReverseMotion = newLimitReverseMotion;
634        return this;
635    }
636    
637    /**
638     * Modifies this Control Request's IgnoreHardwareLimits parameter and returns itself for
639     * method-chaining and easier to use request API.
640     * <p>
641     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
642     * LimitReverseMotion parameters, instead allowing motion.
643     * <p>
644     * This can be useful on mechanisms such as an intake/feeder, where a limit
645     * switch stops motion while intaking but should be ignored when feeding to a
646     * shooter.
647     * <p>
648     * The hardware limit faults and Forward/ReverseLimit signals will still report
649     * the values of the limit switches regardless of this parameter.
650     *
651     * @param newIgnoreHardwareLimits Parameter to modify
652     * @return Itself
653     */
654    public DynamicMotionMagicDutyCycle withIgnoreHardwareLimits(boolean newIgnoreHardwareLimits) {
655        IgnoreHardwareLimits = newIgnoreHardwareLimits;
656        return this;
657    }
658    
659    /**
660     * Modifies this Control Request's IgnoreSoftwareLimits parameter and returns itself for
661     * method-chaining and easier to use request API.
662     * <p>
663     * Set to true to ignore software limits, instead allowing motion.
664     * <p>
665     * This can be useful when calibrating the zero point of a mechanism such as an
666     * elevator.
667     * <p>
668     * The software limit faults will still report the values of the software limits
669     * regardless of this parameter.
670     *
671     * @param newIgnoreSoftwareLimits Parameter to modify
672     * @return Itself
673     */
674    public DynamicMotionMagicDutyCycle withIgnoreSoftwareLimits(boolean newIgnoreSoftwareLimits) {
675        IgnoreSoftwareLimits = newIgnoreSoftwareLimits;
676        return this;
677    }
678    
679    /**
680     * Modifies this Control Request's UseTimesync parameter and returns itself for
681     * method-chaining and easier to use request API.
682     * <p>
683     * Set to true to delay applying this control request until a timesync boundary
684     * (requires Phoenix Pro and CANivore). This eliminates the impact of
685     * nondeterministic network delays in exchange for a larger but deterministic
686     * control latency.
687     * <p>
688     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
689     * Additionally, when this is enabled, the UpdateFreqHz of this request should
690     * be set to 0 Hz.
691     *
692     * @param newUseTimesync Parameter to modify
693     * @return Itself
694     */
695    public DynamicMotionMagicDutyCycle withUseTimesync(boolean newUseTimesync) {
696        UseTimesync = newUseTimesync;
697        return this;
698    }
699
700    /**
701     * Sets the frequency at which this control will update.
702     * This is designated in Hertz, with a minimum of 20 Hz
703     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
704     * Some update frequencies are not supported and will be
705     * promoted up to the next highest supported frequency.
706     * <p>
707     * If this field is set to 0 Hz, the control request will
708     * be sent immediately as a one-shot frame. This may be useful
709     * for advanced applications that require outputs to be
710     * synchronized with data acquisition. In this case, we
711     * recommend not exceeding 50 ms between control calls.
712     *
713     * @param newUpdateFreqHz Parameter to modify
714     * @return Itself
715     */
716    @Override
717    public DynamicMotionMagicDutyCycle withUpdateFreqHz(double newUpdateFreqHz) {
718        UpdateFreqHz = newUpdateFreqHz;
719        return this;
720    }
721
722    /**
723     * Sets the frequency at which this control will update.
724     * This is designated in Hertz, with a minimum of 20 Hz
725     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
726     * Some update frequencies are not supported and will be
727     * promoted up to the next highest supported frequency.
728     * <p>
729     * If this field is set to 0 Hz, the control request will
730     * be sent immediately as a one-shot frame. This may be useful
731     * for advanced applications that require outputs to be
732     * synchronized with data acquisition. In this case, we
733     * recommend not exceeding 50 ms between control calls.
734     *
735     * @param newUpdateFreqHz Parameter to modify
736     * @return Itself
737     */
738    @Override
739    public DynamicMotionMagicDutyCycle withUpdateFreqHz(Frequency newUpdateFreqHz) {
740        UpdateFreqHz = newUpdateFreqHz.in(Hertz);
741        return this;
742    }
743
744    @Override
745    public DynamicMotionMagicDutyCycle clone() {
746        try {
747            return (DynamicMotionMagicDutyCycle)super.clone();
748        } catch (CloneNotSupportedException ex) {
749            /* this should never happen */
750            throw new RuntimeException(ex);
751        }
752    }
753}
754