001/* Copyright (C) Cross The Road Electronics 2024 */
002package com.ctre.phoenix.motorcontrol;
003
004import com.ctre.phoenix.ErrorCode;
005import com.ctre.phoenix.motorcontrol.can.BaseTalon;
006import com.ctre.phoenix.motorcontrol.can.MotControllerJNI;
007
008/**
009 * Collection of sensors available to a motor controller.
010 *
011 * For best performance and update-rate, 
012 * we recommend using the configSelectedFeedbackSensor() and getSelectedSensor*() routines.
013 * However there are occasions where accessing raw sensor values may be useful or convenient.
014 * Particularly if you are seeding one sensor based on another, or need to circumvent sensor-phase.
015 *
016 * Use the getSensorCollection() routine inside your motor controller to create a sensor collection.
017 */
018public class SensorCollection {
019
020        private long _handle;
021
022        /**
023         * Constructor for SensorCollection
024         * @param motorController Motor Controller to connect Collection to
025         */
026        public SensorCollection(BaseTalon motorController) {
027                _handle = motorController.getHandle();
028        }
029
030        /**
031         * Get the position of whatever is in the analog pin of the Talon, regardless of
032         *   whether it is actually being used for feedback.
033         * <p>
034         * This method relies on the Status 4 message, which has a default period of 150ms. For more
035         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
036         *
037         * @return  the 24bit analog value.  The bottom ten bits is the ADC (0 - 1023)
038         *          on the analog pin of the Talon. The upper 14 bits tracks the overflows and underflows
039         *          (continuous sensor).
040         */
041
042        public int getAnalogIn() {
043                return MotControllerJNI.GetAnalogIn(_handle);
044        }
045
046        /**
047         * Sets analog position.
048         *
049         * @param   newPosition The new position.
050         * @param   timeoutMs
051     *            Timeout value in ms. If nonzero, function will wait for
052     *            config success and report an error if it times out.
053     *            If zero, no blocking or checking is performed.
054         *
055         * @return  an ErrorCode.
056         */
057
058        public ErrorCode setAnalogPosition(int newPosition, int timeoutMs) {
059                int retval = MotControllerJNI.SetAnalogPosition(_handle, newPosition, timeoutMs);
060                return ErrorCode.valueOf(retval);
061        }
062
063        /**
064         * Get the position of whatever is in the analog pin of the Talon, regardless of whether
065         *   it is actually being used for feedback.
066         * <p>
067         * This method relies on the Status 4 message, which has a default period of 150ms. For more
068         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
069         *
070         * @return  the ADC (0 - 1023) on analog pin of the Talon.
071         */
072
073        public int getAnalogInRaw() {
074                return MotControllerJNI.GetAnalogInRaw(_handle);
075        }
076
077        /**
078         * Get the velocity of whatever is in the analog pin of the Talon, regardless of
079         *   whether it is actually being used for feedback.
080         * <p>
081         * This method relies on the Status 4 message, which has a default period of 150ms. For more
082         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
083         *
084         * @return  the speed in units per 100ms where 1024 units is one rotation.
085         */
086
087        public int getAnalogInVel() {
088                return MotControllerJNI.GetAnalogInVel(_handle);
089        }
090
091        /**
092         * Get the quadrature position of the Talon, regardless of whether
093         *   it is actually being used for feedback.
094         * <p>
095         * This method relies on the Status 3 message, which has a default period of 150ms. For more
096         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
097         *
098         * @return  the quadrature position.
099         */
100
101        public int getQuadraturePosition() {
102                return MotControllerJNI.GetQuadraturePosition(_handle);
103        }
104
105        /**
106         * Change the quadrature reported position.  Typically this is used to "zero" the
107         *   sensor. This only works with Quadrature sensor.  To set the selected sensor position
108         *   regardless of what type it is, see SetSelectedSensorPosition in the motor controller class.
109         *
110         * @param   newPosition The position value to apply to the sensor.
111         * @param   timeoutMs
112     *            Timeout value in ms. If nonzero, function will wait for
113     *            config success and report an error if it times out.
114     *            If zero, no blocking or checking is performed.
115         *
116         * @return  error code.
117         */
118
119        public ErrorCode setQuadraturePosition(int newPosition, int timeoutMs) {
120                int retval = MotControllerJNI.SetQuadraturePosition(_handle, newPosition, timeoutMs);
121                return ErrorCode.valueOf(retval);
122        }
123
124    
125    /**
126     * Change the quadrature reported position based on pulse width. This can be used to 
127     * effectively make quadrature absolute. For rotary mechanisms with >360 movement (such
128     * as typical swerve modules) bookend0 and bookend1 can be both set to 0 and 
129     * bCrossZeroOnInterval can be set to true. For mechanisms with less than 360 travel (such
130     * as arms), bookend0 and bookend1 should be set to the pulse width values at the two 
131     * extremes. If the interval crosses over the pulse width value of 0 (or any multiple of
132     * 4096), bCrossZeroOnInterval should be true and otherwise should be false. An offset can
133     * also be set.
134     *
135     * @param   bookend0    value at extreme 0
136     * @param   bookend1    value at extreme 1
137     * @param   bCrossZeroOnInterval    True iff zero/wrap-around cross occurs as mechanism moves from bookend0 to bookend1.
138     * @param   offset      (Optional) Value to add to pulse width 
139     * @param   timeoutMs   (Optional) How long to wait for confirmation.  Pass zero so that call
140     *                      does not block.
141     *
142     * @return  error code.
143     */
144
145    public ErrorCode syncQuadratureWithPulseWidth(int bookend0, int bookend1, boolean bCrossZeroOnInterval, int offset, int timeoutMs) {   
146        int ticksPerRevolution = 4096;
147        /* Normalize bookends (should be 0 - ticksPerRevolution) */
148        bookend0 &= (ticksPerRevolution - 1);
149        bookend1 &= (ticksPerRevolution - 1);
150      
151        /* Assign greater and lesser bookend */
152        int greaterBookend;
153        int lesserBookend;
154        
155        if(bookend0 > bookend1)
156        {
157            greaterBookend = bookend0;
158            lesserBookend = bookend1;
159        }
160        else
161        {
162            greaterBookend = bookend1;
163            lesserBookend = bookend0;
164        }
165
166        int average = (greaterBookend + lesserBookend) / 2;
167 
168        /* Get Fractional Part of Pulse Width Position (0 - ticksPerRevolution) */
169        int pulseWidth = getPulseWidthPosition();
170        pulseWidth &= (ticksPerRevolution - 1);
171        
172        if(bCrossZeroOnInterval) 
173        {
174            /*
175             * If the desire is to have the *** part be the interval 
176             * (2048 - 3277 and crosses over 0): 
177             *
178             *                            
179             *                        1024
180             *                     *********    
181             *                    ***********   
182             *                   *************  
183             *                  *************** 
184             *                 *****************
185             *                 *****************
186             *                 *****************
187             *            2048 ***************** 0
188             *                         *********
189             *                         *********
190             *                         *********
191             *                         *********
192             *                        **********
193             *                        ********* 
194             *                        ********  
195             *                       ********   
196             *                       *******
197             *                     3277   
198             *
199             * The goal is to center the discontinuoity between 2048 and 3277 in the blank.
200             * So all pulse width values greater than the avg of the two bookends should be 
201             * reduced by ticksPerRevolution.
202             */
203            if(pulseWidth > average)
204            {            
205                pulseWidth -= ticksPerRevolution;
206            }
207        }
208        else
209        {
210            /*
211             * If the desire is to have the blank part be the interval 
212             * (2048 - 3277 and crosses over 0): 
213             *
214             *                            
215             *                        1024
216             *                     *********    
217             *                    ***********   
218             *                   *************  
219             *                  *************** 
220             *                 *****************
221             *                 *****************
222             *                 *****************
223             *            2048 ***************** 0
224             *                         *********
225             *                         *********
226             *                         *********
227             *                         *********
228             *                        **********
229             *                        ********* 
230             *                        ********  
231             *                       ********   
232             *                       *******
233             *                     3277   
234             *
235             * The goal is to center the discontinuoity between 2048 and 3277 in the ***.
236             * So all pulse width values less than the (ticksPerRevolution / 2 - avg of 
237             * the two bookends) & ticksPerRevolution should be increased by 
238             * ticksPerRevolution.
239             */
240            if(pulseWidth < ((ticksPerRevolution / 2 - average) & 0x0FFF))
241            {            
242                pulseWidth += ticksPerRevolution;
243            }
244        }
245       
246        pulseWidth += offset;
247 
248        return setQuadraturePosition(pulseWidth, timeoutMs);
249    }
250
251    /**
252     * Change the quadrature reported position based on pulse width. This can be used to 
253     * effectively make quadrature absolute. For rotary mechanisms with >360 movement (such
254     * as typical swerve modules) bookend0 and bookend1 can be both set to 0 and 
255     * bCrossZeroOnInterval can be set to true. For mechanisms with less than 360 travel (such
256     * as arms), bookend0 and bookend1 should be set to the pulse width values at the two 
257     * extremes. If the interval crosses over the pulse width value of 0 (or any multiple of
258     * 4096), bCrossZeroOnInterval should be true and otherwise should be false. An offset can
259     * also be set.
260     *
261     * @param   bookend0    value at extreme 0
262     * @param   bookend1    value at extreme 1
263     * @param   bCrossZeroOnInterval    True iff zero/wrap-around cross occurs as mechanism moves from bookend0 to bookend1.
264     *
265     * @return  error code.
266     */
267    public ErrorCode syncQuadratureWithPulseWidth(int bookend0, int bookend1, boolean bCrossZeroOnInterval) {
268        int offset = 0;
269        int timeoutMs = 0;
270        return syncQuadratureWithPulseWidth(bookend0, bookend1, bCrossZeroOnInterval, offset, timeoutMs);
271    }   
272        /**
273         * Get the quadrature velocity, regardless of whether
274         *   it is actually being used for feedback.
275         * <p>
276         * This method relies on the Status 3 message, which has a default period of 150ms. For more
277         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
278         *
279         * @return  the quadrature velocity in units per 100ms.
280         */
281
282        public int getQuadratureVelocity() {
283                return MotControllerJNI.GetQuadratureVelocity(_handle);
284        }
285
286        /**
287         * Gets pulse width position, regardless of whether
288         *   it is actually being used for feedback.
289         * <p>
290         * This method relies on the Status 8 message, which has a default period of 150ms. For more
291         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
292         *
293         * @return  the pulse width position.
294         */
295
296        public int getPulseWidthPosition() {
297                return MotControllerJNI.GetPulseWidthPosition(_handle);
298        }
299
300        /**
301         * Sets pulse width position.
302         *
303         * @param   newPosition The position value to apply to the sensor.
304         * @param   timeoutMs
305     *            Timeout value in ms. If nonzero, function will wait for
306     *            config success and report an error if it times out.
307     *            If zero, no blocking or checking is performed.
308         *
309         * @return  an ErrErrorCode
310         */
311        public ErrorCode setPulseWidthPosition(int newPosition, int timeoutMs) {
312                int retval = MotControllerJNI.SetPulseWidthPosition(_handle, newPosition, timeoutMs);
313                return ErrorCode.valueOf(retval);
314        }
315
316        /**
317         * Gets pulse width velocity, regardless of whether
318         *   it is actually being used for feedback.
319         * <p>
320         * This method relies on the Status 8 message, which has a default period of 150ms. For more
321         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
322         *
323         * @return  the pulse width velocity in units per 100ms (where 4096 units is 1 rotation).
324         */
325
326        public int getPulseWidthVelocity() {
327                return MotControllerJNI.GetPulseWidthVelocity(_handle);
328        }
329
330        /**
331         * Gets pulse width rise to fall time.
332         * <p>
333         * This method relies on the Status 8 message, which has a default period of 150ms. For more
334         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
335         *
336         * @return  the pulse width rise to fall time in microseconds.
337         */
338
339        public int getPulseWidthRiseToFallUs() {
340                return MotControllerJNI.GetPulseWidthRiseToFallUs(_handle);
341        }
342
343        /**
344         * Gets pulse width rise to rise time.
345         * <p>
346         * This method relies on the Status 8 message, which has a default period of 150ms. For more
347         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
348         *
349         * @return  the pulse width rise to rise time in microseconds.
350         */
351
352        public int getPulseWidthRiseToRiseUs() {
353                return MotControllerJNI.GetPulseWidthRiseToRiseUs(_handle);
354        }
355
356        /**
357         * Gets pin state quad a.
358         * <p>
359         * This method relies on the Status 3 message, which has a default period of 150ms. For more
360         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
361         *
362         * @return  the pin state of quad a (1 if asserted, 0 if not asserted).
363         */
364
365        public boolean getPinStateQuadA() {
366                return MotControllerJNI.GetPinStateQuadA(_handle) != 0;
367        }
368
369        /**
370         * Gets pin state quad b.
371         * <p>
372         * This method relies on the Status 3 message, which has a default period of 150ms. For more
373         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
374         *
375         * @return  Digital level of QUADB pin (1 if asserted, 0 if not asserted).
376         */
377
378        public boolean getPinStateQuadB() {
379                return MotControllerJNI.GetPinStateQuadB(_handle) != 0;
380        }
381
382        /**
383         * Gets pin state quad index.
384         * <p>
385         * This method relies on the Status 3 message, which has a default period of 150ms. For more
386         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
387         *
388         * @return  Digital level of QUAD Index pin (1 if asserted, 0 if not asserted).
389         */
390
391        public boolean getPinStateQuadIdx() {
392                return MotControllerJNI.GetPinStateQuadIdx(_handle) != 0;
393        }
394
395        /**
396         * Is forward limit switch closed.
397         * <p>
398         * This method relies on the Status 1 message, which has a default period of 10ms. For more
399         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
400         *
401         * @return  '1' iff forward limit switch is closed, 0 iff switch is open. This function works
402         *          regardless if limit switch feature is enabled.  Remote limit features do not impact this routine.
403         */
404
405        public boolean isFwdLimitSwitchClosed() {
406                return MotControllerJNI.IsFwdLimitSwitchClosed(_handle) != 0;
407        }
408
409        /**
410         * Is reverse limit switch closed.
411         * <p>
412         * This method relies on the Status 1 message, which has a default period of 10ms. For more
413         * information, see: https://phoenix-documentation.readthedocs.io/en/latest/ch18_CommonAPI.html
414         *
415         * @return  '1' iff reverse limit switch is closed, 0 iff switch is open. This function works
416         *          regardless if limit switch feature is enabled.  Remote limit features do not impact this routine.
417         */
418
419        public boolean isRevLimitSwitchClosed() {
420                return MotControllerJNI.IsRevLimitSwitchClosed(_handle) != 0;
421        }
422}