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 * Follow the motor output of another Talon.
022 * <p>
023 * If Talon is in torque control, the torque is copied - which will increase the total torque applied. If
024 * Talon is in percent supply output control, the duty cycle is matched.  Motor direction either matches
025 * master's configured direction or opposes it based on OpposeMasterDirection.
026 */
027public class Follower extends ControlRequest implements Cloneable
028{
029    /**
030     * Device ID of the master to follow.
031     */
032    public int MasterID;
033    /**
034     * Set to false for motor invert to match the master's configured Invert - which
035     * is typical when master and follower are mechanically linked and spin in the
036     * same direction.  Set to true for motor invert to oppose the master's
037     * configured Invert - this is typical where the the master and follower
038     * mechanically spin in opposite directions.
039     */
040    public boolean OpposeMasterDirection;
041
042    /**
043     * The period at which this control will update at.
044     * This is designated in Hertz, with a minimum of 20 Hz
045     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
046     * <p>
047     * If this field is set to 0 Hz, the control request will
048     * be sent immediately as a one-shot frame. This may be useful
049     * for advanced applications that require outputs to be
050     * synchronized with data acquisition. In this case, we
051     * recommend not exceeding 50 ms between control calls.
052     */
053    public double UpdateFreqHz = 20;
054
055    /**
056     * Follow the motor output of another Talon.
057     * <p>
058     * If Talon is in torque control, the torque is copied - which will increase the
059     * total torque applied. If Talon is in percent supply output control, the duty
060     * cycle is matched.  Motor direction either matches master's configured
061     * direction or opposes it based on OpposeMasterDirection.
062     * 
063     * @param MasterID    Device ID of the master to follow.
064     * @param OpposeMasterDirection    Set to false for motor invert to match the
065     *                                 master's configured Invert - which is typical
066     *                                 when master and follower are mechanically
067     *                                 linked and spin in the same direction.  Set
068     *                                 to true for motor invert to oppose the
069     *                                 master's configured Invert - this is typical
070     *                                 where the the master and follower
071     *                                 mechanically spin in opposite directions.
072     */
073    public Follower(int MasterID, boolean OpposeMasterDirection)
074    {
075        super("Follower");
076        this.MasterID = MasterID;
077        this.OpposeMasterDirection = OpposeMasterDirection;
078    }
079
080    @Override
081    public String toString()
082    {
083        String ss = "Control: Follower\n";
084        ss += "    MasterID: " + MasterID + "\n";
085        ss += "    OpposeMasterDirection: " + OpposeMasterDirection + "\n";
086        return ss;
087    }
088
089    @Override
090    public StatusCode sendRequest(String network, int deviceHash)
091    {
092        return StatusCode.valueOf(ControlJNI.JNI_RequestControlFollower(
093                network, deviceHash, UpdateFreqHz, MasterID, OpposeMasterDirection));
094    }
095
096    /**
097     * Gets information about this control request.
098     *
099     * @return Map of control parameter names and corresponding applied values
100     */
101    @Override
102    public Map<String, String> getControlInfo()
103    {
104        var controlInfo = new HashMap<String, String>();
105        controlInfo.put("Name", getName());
106        controlInfo.put("MasterID", String.valueOf(this.MasterID));
107        controlInfo.put("OpposeMasterDirection", String.valueOf(this.OpposeMasterDirection));
108        return controlInfo;
109    }
110    
111    /**
112     * Modifies this Control Request's MasterID parameter and returns itself for
113     * method-chaining and easier to use request API.
114     * <p>
115     * Device ID of the master to follow.
116     *
117     * @param newMasterID Parameter to modify
118     * @return Itself
119     */
120    public Follower withMasterID(int newMasterID)
121    {
122        MasterID = newMasterID;
123        return this;
124    }
125    
126    /**
127     * Modifies this Control Request's OpposeMasterDirection parameter and returns itself for
128     * method-chaining and easier to use request API.
129     * <p>
130     * Set to false for motor invert to match the master's configured Invert - which
131     * is typical when master and follower are mechanically linked and spin in the
132     * same direction.  Set to true for motor invert to oppose the master's
133     * configured Invert - this is typical where the the master and follower
134     * mechanically spin in opposite directions.
135     *
136     * @param newOpposeMasterDirection Parameter to modify
137     * @return Itself
138     */
139    public Follower withOpposeMasterDirection(boolean newOpposeMasterDirection)
140    {
141        OpposeMasterDirection = newOpposeMasterDirection;
142        return this;
143    }
144
145    /**
146     * Sets the period at which this control will update at.
147     * This is designated in Hertz, with a minimum of 20 Hz
148     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
149     * <p>
150     * If this field is set to 0 Hz, the control request will
151     * be sent immediately as a one-shot frame. This may be useful
152     * for advanced applications that require outputs to be
153     * synchronized with data acquisition. In this case, we
154     * recommend not exceeding 50 ms between control calls.
155     *
156     * @param newUpdateFreqHz Parameter to modify
157     * @return Itself
158     */
159    @Override
160    public Follower withUpdateFreqHz(double newUpdateFreqHz)
161    {
162        UpdateFreqHz = newUpdateFreqHz;
163        return this;
164    }
165
166    /**
167     * Sets the period at which this control will update at.
168     * This is designated in Hertz, with a minimum of 20 Hz
169     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
170     * <p>
171     * If this field is set to 0 Hz, the control request will
172     * be sent immediately as a one-shot frame. This may be useful
173     * for advanced applications that require outputs to be
174     * synchronized with data acquisition. In this case, we
175     * recommend not exceeding 50 ms between control calls.
176     *
177     * @param newUpdateFreqHz Parameter to modify
178     * @return Itself
179     */
180    @Override
181    public Follower withUpdateFreqHz(Frequency newUpdateFreqHz)
182    {
183        UpdateFreqHz = newUpdateFreqHz.in(Hertz);
184        return this;
185    }
186
187    @Override
188    public Follower clone()
189    {
190        try {
191            return (Follower)super.clone();
192        } catch (CloneNotSupportedException ex) {
193            /* this should never happen */
194            throw new RuntimeException(ex);
195        }
196    }
197}
198