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.hardware; 008 009import com.ctre.phoenixpro.BaseStatusSignalValue; 010import com.ctre.phoenix6.StatusCode; 011import com.ctre.phoenixpro.StatusSignalValue; 012import com.ctre.phoenixpro.controls.ControlRequest; 013import com.ctre.phoenixpro.controls.EmptyControl; 014import com.ctre.phoenix6.jni.CtreJniWrapper; 015import com.ctre.phoenix6.jni.ErrorReportingJNI; 016 017import java.util.Map; 018import java.util.concurrent.ConcurrentHashMap; 019import java.util.concurrent.locks.Lock; 020import java.util.concurrent.locks.ReentrantLock; 021 022/** 023 * @deprecated Classes in the phoenixpro package will be removed in 2024. 024 * Users should instead use classes from the phoenix6 package. 025 */ 026@Deprecated(forRemoval = true) 027public abstract class ParentDevice extends CtreJniWrapper { 028 protected static final double kDefaultControlRatePeriodsSec = 0.010; 029 030 private final Map<Integer, BaseStatusSignalValue> _signalValues = new ConcurrentHashMap<Integer, BaseStatusSignalValue>(); 031 private ControlRequest _controlReq = new EmptyControl(); 032 private final Lock _controlReqLck = new ReentrantLock(); 033 034 protected final DeviceIdentifier deviceIdentifier; 035 036 protected abstract void reportIfTooOld(); 037 038 /** 039 * @deprecated Classes in the phoenixpro package will be removed in 2024. 040 * Users should instead use classes from the phoenix6 package. 041 */ 042 @Deprecated(forRemoval = true) 043 public interface MapGenerator<T> { 044 Map<Integer, StatusSignalValue<T>> run(); 045 } 046 047 /** 048 * @deprecated Classes in the phoenixpro package will be removed in 2024. 049 * Users should instead use classes from the phoenix6 package. 050 */ 051 @Deprecated(forRemoval = true) 052 public ParentDevice(int deviceID, String model, String canbus) { 053 this.deviceIdentifier = new DeviceIdentifier(deviceID, model, canbus); 054 } 055 056 /** 057 * @return the device ID of this device [0,62]. 058 */ 059 public int getDeviceID() { 060 return deviceIdentifier.deviceID; 061 } 062 063 /** 064 * @return name of the CAN bus this device is on. 065 */ 066 public String getCANBus() { 067 return deviceIdentifier.network; 068 } 069 070 protected StatusCode setControlPrivate(ControlRequest request) { 071 StatusCode status; 072 073 _controlReqLck.lock(); 074 /* make sure we always unlock */ 075 try { 076 reportIfTooOld(); 077 078 boolean cancelOtherRequests = false; 079 if (request.getControlInfo().getNameValues().get("name") != getAppliedControl() 080 .getControlInfo().getNameValues().get("name")) { 081 cancelOtherRequests = true; 082 } 083 084 _controlReq = request; 085 status = _controlReq.sendRequest(deviceIdentifier.network, deviceIdentifier.deviceHash, 086 cancelOtherRequests); 087 } finally { 088 _controlReqLck.unlock(); 089 } 090 091 if (!status.isOK()) { 092 ErrorReportingJNI.reportStatusCode(status.value, deviceIdentifier.toString() + " SetControl " 093 + request.getControlInfo().getNameValues().get("name")); 094 } 095 return status; 096 } 097 098 /** 099 * Get the latest applied control 100 * 101 * @return Latest applied control 102 */ 103 public ControlRequest getAppliedControl() { 104 return _controlReq; 105 } 106 107 private <T> StatusSignalValue<T> commonLookup(int spn, Class<T> classOfSignal, int mapIter, 108 MapGenerator<T> generator, String signalName, boolean reportOnConstruction) { 109 int totalHash = spn | (mapIter << 16); 110 /* lookup and return if found */ 111 BaseStatusSignalValue toFind; 112 if (_signalValues.containsKey(totalHash)) { 113 /* Found it, toFind is now the found StatusSignalValue */ 114 toFind = _signalValues.get(totalHash); 115 /* since we didn't construct, report errors */ 116 reportOnConstruction = true; 117 } else { 118 /* insert into map */ 119 if (mapIter == 0) { 120 _signalValues.put(totalHash, 121 new StatusSignalValue<T>(deviceIdentifier, spn, () -> { 122 reportIfTooOld(); 123 }, classOfSignal, signalName)); 124 } else { 125 _signalValues.put(totalHash, 126 new StatusSignalValue<T>(deviceIdentifier, spn, () -> { 127 reportIfTooOld(); 128 }, classOfSignal, generator, signalName)); 129 } 130 131 /* look up and return */ 132 toFind = _signalValues.get(totalHash); 133 } 134 /* Try to return the found value cast to the child class */ 135 136 /* Turn off unchecked warning, we check the type afterwards */ 137 @SuppressWarnings("unchecked") 138 StatusSignalValue<T> toReturn = StatusSignalValue.class.cast(toFind); 139 140 if (toReturn == null) { 141 /* Cast failed, so return with error */ 142 return new StatusSignalValue<T>(classOfSignal, StatusCode.InvalidParamValue); 143 } else if (toReturn.getTypeClass().equals(classOfSignal)) { 144 /* Refresh the signal before we pass it down */ 145 toReturn.refresh(reportOnConstruction); 146 /* We're good, go ahead and return */ 147 return toReturn; 148 } else { 149 /* Type does not match, return with error */ 150 return new StatusSignalValue<T>(classOfSignal, StatusCode.InvalidParamValue); 151 } 152 } 153 154 protected <T> StatusSignalValue<T> lookupStatusSignalValue(int spn, Class<T> classOfSignal, String signalName, boolean reportOnConstruction) { 155 return commonLookup(spn, classOfSignal, 0, null, signalName, reportOnConstruction); 156 } 157 158 protected <T> StatusSignalValue<T> lookupStatusSignalValue(int spn, Class<T> classOfSignal, int mapIter, 159 MapGenerator<T> generator, String signalName, boolean reportOnConstruction) { 160 return commonLookup(spn, classOfSignal, mapIter, generator, signalName, reportOnConstruction); 161 } 162}