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.phoenixpro; 008 009import com.ctre.phoenix6.StatusCode; 010import com.ctre.phoenixpro.Timestamp.TimestampSource; 011import com.ctre.phoenixpro.hardware.DeviceIdentifier; 012import com.ctre.phoenix6.jni.ErrorReportingJNI; 013import com.ctre.phoenix6.jni.StatusSignalJNI; 014 015/** 016 * Class that provides operations to retrieve 017 * information about a status signal. 018 * 019 * @deprecated BaseStatusSignalValue has been renamed to BaseStatusSignal. 020 * Additionally, Classes in the phoenixpro package will be removed in 2024. 021 * Users should instead use classes from the phoenix6 package. 022 */ 023@Deprecated(forRemoval = true) 024public abstract class BaseStatusSignalValue { 025 protected DeviceIdentifier deviceIdentifier; 026 protected int spn; 027 protected String units; 028 protected StatusCode error = StatusCode.StatusCodeNotInitialized; 029 protected double baseValue = 0; 030 protected AllTimestamps timestamps = new AllTimestamps(); 031 protected final String signalName; 032 033 protected StatusSignalJNI jni = new StatusSignalJNI(); 034 035 BaseStatusSignalValue(DeviceIdentifier deviceIdentifier, int spn, String signalName) { 036 this.deviceIdentifier = deviceIdentifier; 037 this.spn = spn; 038 this.signalName = signalName; 039 040 jni.deviceHash = deviceIdentifier.getDeviceHash(); 041 jni.spn = spn; 042 043 this.units = jni.JNI_GetUnits(); 044 } 045 046 /* Constructor for an invalid BaseStatusSignalValue */ 047 BaseStatusSignalValue(StatusCode error) { 048 this(new DeviceIdentifier(), 0, "Invalid"); 049 this.error = error; 050 } 051 052 protected void copyFrom(BaseStatusSignalValue other) { 053 this.units = other.units; 054 this.error = other.error; 055 this.baseValue = other.baseValue; 056 this.timestamps = other.timestamps; 057 // Don't copy the signal name since the user expects the original name 058 } 059 060 /** 061 * Waits for new data on all provided signals up to timeout. 062 * This API is typically used with CANivore Bus signals as they will be synced using the 063 * CANivore Timesync feature and arrive simultaneously. Signals on a roboRIO bus cannot 064 * be synced and may require a significantly longer blocking call to receive all signals. 065 * 066 * This can also be used with a timeout of zero to refresh many signals at once, which 067 * is faster than calling refresh() on every signal. 068 * 069 * @param timeoutSeconds Maximum time to wait for new data in seconds. 070 * Pass zero to refresh all signals without blocking. 071 * @param signals Signals to wait for new data against 072 * @return An InvalidParamValue if signals array is empty, 073 * InvalidNetwork if signals are on different CAN bus networks, 074 * RxTimeout if it took longer than timeoutSeconds to receive all the signals, 075 * MultiSignalNotSupported if using the roboRIO bus with more than one signal and a non-zero timeout. 076 * An OK status code means that all signals arrived within timeoutSeconds and they are all OK. 077 * 078 * Any other value represents the StatusCode of the first failed signal. 079 * Call getError() on each signal to determine which ones failed. 080 */ 081 public static StatusCode waitForAll(double timeoutSeconds, BaseStatusSignalValue... signals) { 082 String network = ""; 083 boolean first = true; 084 if (signals.length < 1) 085 { 086 /* We don't have any signals to wait for, so return early */ 087 ErrorReportingJNI.reportStatusCode(StatusCode.InvalidParamValue.value, "ctre.phoenixpro.BaseStatusSignalValue.waitForAll"); 088 return StatusCode.InvalidParamValue; 089 } 090 StatusSignalJNI[] toGet = new StatusSignalJNI[signals.length]; 091 for (int i = 0; i < signals.length; ++i) { 092 var sig = signals[i]; 093 if (first) { 094 network = sig.deviceIdentifier.getNetwork(); 095 first = false; 096 } else if (!sig.deviceIdentifier.getNetwork().equals(network)) { 097 // Networks don't match, return early 098 ErrorReportingJNI.reportStatusCode(StatusCode.InvalidNetwork.value, "ctre.phoenixpro.BaseStatusSignalValue.waitForAll"); 099 return StatusCode.InvalidNetwork; 100 } 101 toGet[i] = sig.jni; 102 } 103 int err = StatusSignalJNI.JNI_WaitForAll(network, timeoutSeconds, toGet); 104 for (int i = 0; i < signals.length; ++i) { 105 signals[i].spn = toGet[i].spn; 106 signals[i].error = StatusCode.valueOf(toGet[i].statusCode); 107 signals[i].baseValue = toGet[i].value; 108 signals[i].timestamps.update(toGet[i].swtimeStampSeconds, TimestampSource.System, true, 109 toGet[i].hwtimeStampSeconds, TimestampSource.CANivore, true, 110 0, null, false); 111 } 112 StatusCode retval = StatusCode.valueOf(err); 113 if (false == retval.isOK()) { 114 ErrorReportingJNI.reportStatusCode(retval.value, "ctre.phoenixpro.BaseStatusSignalValue.waitForAll"); 115 } 116 return StatusCode.valueOf(err); 117 } 118 /** 119 * Performs latency compensation on signal using the signalSlope and signal's latency to determine 120 * the magnitude of compensation. The caller must refresh these StatusSignalValues beforehand; 121 * this function only does the math required for latency compensation. 122 * <p> 123 * <b>Important</b>: The signalSlope must be the rate of change of the signal. If it is not the latency 124 * compensation may not perform as expected. 125 * <p> 126 * <b>Example</b>: 127 * double compensatedTurns = getLatencyCompensatedValue(fx.getPosition(), fx.getVelocity()); 128 * 129 * @param signal Signal to be latency compensated. Caller must make sure this signal is up to date 130 * either by calling {@link StatusSignalValue#refresh()} or {@link StatusSignalValue#waitForUpdate(double)}. 131 * @param signalSlope Derivative of signal that informs compensation magnitude. Caller must make sure this 132 * signal is up to date either by calling {@link StatusSignalValue#refresh()} or 133 * {@link StatusSignalValue#waitForUpdate(double)}. 134 * @return Latency compensated value from the signal StatusSignalValue. 135 */ 136 public static double getLatencyCompensatedValue(StatusSignalValue<Double> signal, StatusSignalValue<Double> signalSlope) 137 { 138 double nonCompensatedSignal = signal.getValue(); 139 double changeInSignal = signalSlope.getValue(); 140 double latency = signal.getTimestamp().getLatency(); 141 return nonCompensatedSignal + (changeInSignal * latency); 142 } 143 144 /** 145 * Checks if all signals have an OK error code. 146 * 147 * @param signals Signals to check error code of. 148 * @return True if all are good, false otherwise 149 */ 150 public static boolean isAllGood(BaseStatusSignalValue... signals) { 151 for (BaseStatusSignalValue sig : signals) { 152 if (!sig.getError().isOK()) 153 return false; 154 } 155 return true; 156 } 157 158 /** 159 * Sets the rate at which the device will publish this signal. 160 * <p> 161 * The minimum supported signal frequency is 4 Hz, and the maximum is 1000 Hz. 162 * <p> 163 * This will wait up to 0.050 seconds (50ms) by default. 164 * 165 * @param frequencyHz Rate to publish the signal in Hz. 166 * @return Status code of setting the update frequency 167 */ 168 public StatusCode setUpdateFrequency(double frequencyHz) { 169 return setUpdateFrequency(frequencyHz, 0.050); 170 } 171 172 /** 173 * Sets the rate at which the device will publish this signal. 174 * <p> 175 * The minimum supported signal frequency is 4 Hz, and the maximum is 1000 Hz. 176 * 177 * @param frequencyHz Rate to publish the signal in Hz. 178 * @param timeoutSeconds Maximum amount of time to wait when performing the action 179 * @return Status code of setting the update frequency 180 */ 181 public StatusCode setUpdateFrequency(double frequencyHz, double timeoutSeconds) { 182 /* attempt to change the period */ 183 return StatusCode.valueOf(jni.JNI_SetUpdateFrequency(this.deviceIdentifier.getNetwork(), frequencyHz, timeoutSeconds)); 184 } 185 186 /** 187 * Gets the units for this signal 188 * 189 * @return String representation of units for this signal 190 */ 191 public String getUnits() { 192 return units; 193 } 194 195 /** 196 * Get all timestamps relevant for this signal 197 * 198 * @return All timestamps available for this signal 199 */ 200 public AllTimestamps getAllTimestamps() { 201 return timestamps; 202 } 203 204 /** 205 * Get the best available timestamp for this signal 206 * 207 * @return Best available timestamp 208 */ 209 public Timestamp getTimestamp() { 210 return timestamps.getBestTimestamp(); 211 } 212 213 /** 214 * Get the error code from when we last received this signal 215 * 216 * @return Last cached Error Code 217 */ 218 public StatusCode getError() { 219 return error; 220 } 221};