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;
008
009import com.ctre.phoenix6.jni.CANBusJNI;
010
011/**
012 * Class for getting information about an available CAN bus.
013 */
014public class CANBus {
015    /**
016     * Contains status information about a CAN bus.
017     */
018    public static class CANBusStatus {
019        /**
020         * Status code response of getting the data
021         */
022        public StatusCode Status;
023
024        /**
025         * CAN bus utilization, from 0.0 to 1.0
026         */
027        public float BusUtilization;
028        /**
029         * Bus off count
030         */
031        public int BusOffCount;
032        /**
033         * Transmit buffer full count
034         */
035        public int TxFullCount;
036        /**
037         * Receive Error Counter (REC)
038         */
039        public int REC;
040        /**
041         * Transmit Error Counter (TEC)
042         */
043        public int TEC;
044    }
045
046    private final String _name;
047    private final CANBusStatus _status = new CANBusStatus();
048    private final CANBusJNI _jni = new CANBusJNI();
049
050    /**
051     * Creates a new CAN bus with the given name.
052     *
053     * @param canbus    Name of the CAN bus. Possible CAN bus strings are:
054     *                  <ul>
055     *                    <li>"rio" for the native roboRIO CAN bus
056     *                    <li>CANivore name or serial number
057     *                    <li>SocketCAN interface (non-FRC Linux only)
058     *                    <li>"*" for any CANivore seen by the program
059     *                    <li>empty string (default) to select the default for the system:
060     *                    <ul>
061     *                      <li>"rio" on roboRIO
062     *                      <li>"can0" on Linux
063     *                      <li>"*" on Windows
064     *                    </ul>
065     *                  </ul>
066     */
067    public CANBus(String canbus) {
068        _name = canbus;
069    }
070
071    /**
072     * Creates a new CAN bus using the default for the system:
073     * <ul>
074     *   <li>"rio" on roboRIO
075     *   <li>"can0" on Linux
076     *   <li>"*" on Windows
077     * </ul>
078     */
079    public CANBus() {
080        this("");
081    }
082
083    /**
084     * Creates a new CAN bus with the given name, and loads an associated
085     * hoot file for replay (equivalent to {@link HootReplay#loadFile}).
086     * <p>
087     * Only one hoot log may be replayed at a time. As a result, only one
088     * CAN bus should be constructed with a hoot file.
089     * <p>
090     * When using relative paths, the file path is typically relative
091     * to the top-level folder of the robot project.
092     *
093     * @param canbus    Name of the CAN bus. Possible CAN bus strings are:
094     *                  <ul>
095     *                    <li>"rio" for the native roboRIO CAN bus
096     *                    <li>CANivore name or serial number
097     *                    <li>SocketCAN interface (non-FRC Linux only)
098     *                    <li>"*" for any CANivore seen by the program
099     *                    <li>empty string (default) to select the default for the system:
100     *                    <ul>
101     *                      <li>"rio" on roboRIO
102     *                      <li>"can0" on Linux
103     *                      <li>"*" on Windows
104     *                    </ul>
105     *                  </ul>
106     * @param hootFilepath Path and name of the hoot file to load
107     */
108    public CANBus(String canbus, String hootFilepath) {
109        this(canbus);
110        HootReplay.loadFile(hootFilepath);
111    }
112
113    /**
114     * Get the name used to construct this CAN bus.
115     *
116     * @return Name of the CAN bus
117     */
118    public String getName() {
119        return _name;
120    }
121
122    /**
123     * Gets whether the network is CAN FD.
124     *
125     * @return True if the network is CAN FD
126     */
127    public boolean isNetworkFD() {
128        return CANBusJNI.JNI_IsNetworkFD(_name);
129    }
130
131    /**
132     * Gets the status of the CAN bus, including the
133     * bus utilization and the error counters.
134     * <p>
135     * This can block for up to 0.001 seconds (1 ms).
136     * <p>
137     * This function refreshes and returns a cached object.
138     *
139     * @return Status of the CAN bus
140     */
141    public CANBusStatus getStatus() {
142        var err = _jni.JNI_GetStatus(_name);
143
144        _status.BusUtilization = _jni.busUtilization;
145        _status.BusOffCount = _jni.busOffCount;
146        _status.TxFullCount = _jni.txFullCount;
147        _status.REC = _jni.rec;
148        _status.TEC = _jni.tec;
149
150        if (err != 0) {
151            _status.Status = StatusCode.InvalidNetwork;
152        } else {
153            _status.Status = StatusCode.OK;
154        }
155        return _status;
156    }
157
158    /**
159     * Gets whether the network is CAN FD.
160     *
161     * @deprecated The CANBus static methods are deprecated
162     * for removal in 2026. Construct a new CANBus instance
163     * and call {@link #isNetworkFD()} instead.
164     *
165     * @param canbus Name of the CAN bus
166     * @return True if the network is CAN FD
167     */
168    @Deprecated(forRemoval = true)
169    public static boolean isNetworkFD(String canbus) {
170        return CANBusJNI.JNI_IsNetworkFD(canbus);
171    }
172    /**
173     * Gets the status of the CAN bus, including the
174     * bus utilization and the error counters.
175     * <p>
176     * This function returns a new object every call.
177     * As a result, we recommend that this is not called
178     * inside a tight loop.
179     *
180     * @deprecated The CANBus static methods are deprecated
181     * for removal in 2026. Construct a new CANBus instance
182     * and call {@link #getStatus()} instead.
183     *
184     * @param canbus Name of the CAN bus
185     * @return Status of the CAN bus
186     */
187    @Deprecated(forRemoval = true)
188    public static CANBusStatus getStatus(String canbus) {
189        var jni = new CANBusJNI();
190        var err = jni.JNI_GetStatus(canbus);
191
192        var status = new CANBusStatus();
193        status.BusUtilization = jni.busUtilization;
194        status.BusOffCount = jni.busOffCount;
195        status.TxFullCount = jni.txFullCount;
196        status.REC = jni.rec;
197        status.TEC = jni.tec;
198
199        if (err != 0) {
200            status.Status = StatusCode.InvalidNetwork;
201        } else {
202            status.Status = StatusCode.OK;
203        }
204        return status;
205    }
206}