001package jmri.jmrix.can.cbus; 002 003import java.util.HashMap; 004import javax.annotation.Nonnull; 005import jmri.jmrix.AbstractMessage; 006import jmri.jmrix.can.cbus.swing.CbusFilterFrame; 007import jmri.util.ThreadingUtil; 008 009// import org.slf4j.Logger; 010// import org.slf4j.LoggerFactory; 011 012/** 013 * Class to implement filtering of CBUS frames. 014 * Long event OPCs are not altered for a node number of 0 015 * @author Steve Young (C) 2018, 2020 016 */ 017public class CbusFilter { 018 private final HashMap<Integer, Boolean> _boolean_hash_map; 019 private final CbusFilterFrame _filterFrame; 020 private final HashMap<Integer, Integer> _nodes_hashmap; 021 private int _evMin = 0; 022 private int _evMax = 0; 023 private int _ndMin = 0; 024 private int _ndMax = 0; 025 026 public static final int CFMAXCATS =CbusFilterType.values().length; 027 public static final int CFMAX_NODES = 100; 028 029 /** 030 * Creates a new instance of CbusFilter 031 * @param filterFrame The Instance Frame 032 */ 033 public CbusFilter(CbusFilterFrame filterFrame) { 034 _filterFrame = filterFrame; 035 _boolean_hash_map = new HashMap<>(getHMapSize(CFMAXCATS + CFMAX_NODES)); 036 _nodes_hashmap = new HashMap<>(getHMapSize(CFMAX_NODES)); 037 for ( int i=0 ; (i < CFMAXCATS + CFMAX_NODES) ; i++){ 038 _boolean_hash_map.put(i,false); 039 } 040 } 041 042 /** 043 * Filter CanMessage or CanReply. 044 * 045 * @param test Message to Test 046 * @return Filter number which failed, else -1 047 */ 048 public int filter( @Nonnull AbstractMessage test) { 049 for (CbusFilterType singleFilter : CbusFilterType.allFilters(test.getElement(0))) { 050 int _toReturn = singleFilter.action(test,this); 051 if (_toReturn>-1){ 052 return _toReturn; 053 } 054 else if (_toReturn==-2){ // Extended or RTR CAN Frame, No OPC's to filter. 055 break; 056 } 057 } 058 return -1; 059 } 060 061 /** 062 * Get position in Node List for a given Node Number 063 * @param node Node Number 064 * @param nodes Main Node map. 065 * @return ID used in main Boolean filter list / CbusFilterPanel ID 066 */ 067 private static int positionInNodeList(int node, @Nonnull HashMap<Integer,Integer> nodes){ 068 for (var o : nodes.entrySet()) { 069 if (o.getValue().equals(node)) { 070 return o.getKey(); 071 } 072 } 073 return -1; 074 } 075 076 /** 077 * Get the main Filter Frame. 078 * @return CbusFilterFrame instance 079 */ 080 protected CbusFilterFrame getCbusFilterFrame() { 081 return _filterFrame; 082 } 083 084 /** 085 * Get Map of Filters. 086 * @return Map of Boolean values. 087 */ 088 protected final HashMap<Integer,Boolean> getActiveFilters(){ 089 return _boolean_hash_map; 090 } 091 092 /** 093 * Get Map of Nodes. 094 * @return Map of Node Numbers. 095 */ 096 protected final HashMap<Integer,Integer> getNodes() { 097 return _nodes_hashmap; 098 } 099 100 /** 101 * Perform Node checks for a given node number. 102 * If a new Node Number is found, is added to the main Node List 103 * and a new filter created. 104 * 105 * @param node Node Number 106 * @param cf CbusFilter instance 107 * @return Filter number which failed, else -1 108 */ 109 protected static int checknode(int node,@Nonnull CbusFilter cf) { 110 111 if (!cf.getNodes().containsValue(node)){ 112 cf.getNodes().put(cf.getNodes().size()+ CFMAXCATS,node); 113 // log.info("added new node {} to position {}",node,positionInNodeList(node,cf.getNodes())); 114 if (cf.getCbusFilterFrame() !=null) { 115 cf.getCbusFilterFrame().addNode(node,(positionInNodeList(node,cf.getNodes()))); 116 } 117 } 118 119 if ( cf.getActiveFilters().get(CbusFilterType.CFNODE.ordinal())){ 120 return CbusFilterType.CFNODE.ordinal(); 121 } else { 122 incrementCount(CbusFilterType.CFNODE.ordinal(),cf); } 123 if ( cf.getActiveFilters().get(positionInNodeList(node,cf.getNodes())) ){ 124 return positionInNodeList(node,cf.getNodes()); 125 } else { 126 incrementCount(positionInNodeList(node,cf.getNodes()),cf); } 127 return -1; 128 } 129 130 /** 131 * Increment Filter count for a given filter ID. 132 * @param filternum Filter ID 133 * @param cf CbusFilter instance 134 */ 135 protected static void incrementCount(int filternum, @Nonnull CbusFilter cf){ 136 // log.debug("increment count {}",filternum); 137 if (cf.getCbusFilterFrame() != null ) { 138 ThreadingUtil.runOnGUIEventually( ()->{ 139 cf.getCbusFilterFrame().passIncrement(filternum); 140 }); 141 } 142 } 143 144 /** 145 * Set a single Filter to pass or filter. 146 * @param id Filter ID 147 * @param trueorfalse true to filter, false to pass through. 148 */ 149 public void setFilter(int id, boolean trueorfalse) { 150 _boolean_hash_map.put(id, trueorfalse); 151 } 152 153 /** 154 * Set the event or node min and max values. 155 * 156 * @param filter CFEVENTMIN, CFEVENTMAX, CFNODEMIN or CFNODEMAX 157 * @param val min or max value 158 */ 159 public void setMinMax(@Nonnull CbusFilterType filter, int val){ 160 switch (filter) { 161 case CFEVENTMIN: 162 _evMin = val; 163 break; 164 case CFEVENTMAX: 165 _evMax = val; 166 break; 167 case CFNODEMIN: 168 _ndMin = val; 169 break; 170 case CFNODEMAX: 171 _ndMax = val; 172 break; 173 default: 174 break; 175 } 176 } 177 178 /** 179 * Get Minimum Event Number. 180 * @return Minimum Event 181 */ 182 public int getEvMin() { 183 return _evMin; 184 } 185 186 /** 187 * Get Maximum Event Number. 188 * @return Maximum Event 189 */ 190 public int getEvMax() { 191 return _evMax; 192 } 193 194 /** 195 * Get Minimum Node Number. 196 * @return Minimum Node 197 */ 198 public int getNdMin() { 199 return _ndMin; 200 } 201 202 /** 203 * Get Maximum Node Number. 204 * @return Maximum Node 205 */ 206 public int getNdMax() { 207 return _ndMax; 208 } 209 210 /** 211 * Get optimum HashMap Size. 212 * @param reqdCapacity Required finite capacity 213 * @return value to use on creation 214 */ 215 public static final int getHMapSize(int reqdCapacity){ 216 return ((reqdCapacity*4+2)/3); 217 } 218 219 // private final static Logger log = LoggerFactory.getLogger(CbusFilter.class); 220}