001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj; 006 007import static edu.wpi.first.util.ErrorMessages.requireNonNullParam; 008 009import edu.wpi.first.hal.FRCNetComm.tResourceType; 010import edu.wpi.first.hal.HAL; 011import edu.wpi.first.networktables.MultiSubscriber; 012import edu.wpi.first.networktables.NetworkTable; 013import edu.wpi.first.networktables.NetworkTableEntry; 014import edu.wpi.first.networktables.NetworkTableEvent; 015import edu.wpi.first.networktables.NetworkTableInstance; 016import edu.wpi.first.networktables.NetworkTableListener; 017import edu.wpi.first.networktables.StringPublisher; 018import edu.wpi.first.networktables.Topic; 019import java.util.Collection; 020import java.util.EnumSet; 021 022/** 023 * The preferences class provides a relatively simple way to save important values to the roboRIO to 024 * access the next time the roboRIO is booted. 025 * 026 * <p>This class loads and saves from a file inside the roboRIO. The user can not access the file 027 * directly, but may modify values at specific fields which will then be automatically saved to the 028 * file by the NetworkTables server. 029 * 030 * <p>This class is thread safe. 031 * 032 * <p>This will also interact with {@link NetworkTable} by creating a table called "Preferences" 033 * with all the key-value pairs. 034 */ 035public final class Preferences { 036 /** The Preferences table name. */ 037 private static final String TABLE_NAME = "Preferences"; 038 /** The network table. */ 039 private static NetworkTable m_table; 040 041 private static StringPublisher m_typePublisher; 042 private static MultiSubscriber m_tableSubscriber; 043 private static NetworkTableListener m_listener; 044 045 /** Creates a preference class. */ 046 private Preferences() {} 047 048 static { 049 setNetworkTableInstance(NetworkTableInstance.getDefault()); 050 HAL.report(tResourceType.kResourceType_Preferences, 0); 051 } 052 053 /** 054 * Set the NetworkTable instance used for entries. For testing purposes; use with caution. 055 * 056 * @param inst NetworkTable instance 057 */ 058 public static synchronized void setNetworkTableInstance(NetworkTableInstance inst) { 059 m_table = inst.getTable(TABLE_NAME); 060 if (m_typePublisher != null) { 061 m_typePublisher.close(); 062 } 063 m_typePublisher = m_table.getStringTopic(".type").publish(); 064 m_typePublisher.set("RobotPreferences"); 065 066 // Subscribe to all Preferences; this ensures we get the latest values 067 // ahead of a getter call. 068 if (m_tableSubscriber != null) { 069 m_tableSubscriber.close(); 070 } 071 m_tableSubscriber = new MultiSubscriber(inst, new String[] {m_table.getPath() + "/"}); 072 073 // Listener to set all Preferences values to persistent 074 // (for backwards compatibility with old dashboards). 075 if (m_listener != null) { 076 m_listener.close(); 077 } 078 m_listener = 079 NetworkTableListener.createListener( 080 m_tableSubscriber, 081 EnumSet.of(NetworkTableEvent.Kind.kImmediate, NetworkTableEvent.Kind.kPublish), 082 event -> { 083 if (event.topicInfo != null) { 084 Topic topic = event.topicInfo.getTopic(); 085 if (!topic.equals(m_typePublisher.getTopic())) { 086 event.topicInfo.getTopic().setPersistent(true); 087 } 088 } 089 }); 090 } 091 092 /** 093 * Gets the preferences keys. 094 * 095 * @return a collection of the keys 096 */ 097 public static Collection<String> getKeys() { 098 return m_table.getKeys(); 099 } 100 101 /** 102 * Puts the given string into the preferences table. 103 * 104 * @param key the key 105 * @param value the value 106 * @throws NullPointerException if value is null 107 */ 108 public static void setString(String key, String value) { 109 requireNonNullParam(value, "value", "setString"); 110 111 NetworkTableEntry entry = m_table.getEntry(key); 112 entry.setString(value); 113 entry.setPersistent(); 114 } 115 116 /** 117 * Puts the given string into the preferences table if it doesn't already exist. 118 * 119 * @param key The key 120 * @param value The value 121 */ 122 public static void initString(String key, String value) { 123 NetworkTableEntry entry = m_table.getEntry(key); 124 entry.setDefaultString(value); 125 entry.setPersistent(); 126 } 127 128 /** 129 * Puts the given int into the preferences table. 130 * 131 * @param key the key 132 * @param value the value 133 */ 134 public static void setInt(String key, int value) { 135 NetworkTableEntry entry = m_table.getEntry(key); 136 entry.setDouble(value); 137 entry.setPersistent(); 138 } 139 140 /** 141 * Puts the given int into the preferences table if it doesn't already exist. 142 * 143 * @param key The key 144 * @param value The value 145 */ 146 public static void initInt(String key, int value) { 147 NetworkTableEntry entry = m_table.getEntry(key); 148 entry.setDefaultDouble(value); 149 entry.setPersistent(); 150 } 151 152 /** 153 * Puts the given double into the preferences table. 154 * 155 * @param key the key 156 * @param value the value 157 */ 158 public static void setDouble(String key, double value) { 159 NetworkTableEntry entry = m_table.getEntry(key); 160 entry.setDouble(value); 161 entry.setPersistent(); 162 } 163 164 /** 165 * Puts the given double into the preferences table if it doesn't already exist. 166 * 167 * @param key The key 168 * @param value The value 169 */ 170 public static void initDouble(String key, double value) { 171 NetworkTableEntry entry = m_table.getEntry(key); 172 entry.setDefaultDouble(value); 173 entry.setPersistent(); 174 } 175 176 /** 177 * Puts the given float into the preferences table. 178 * 179 * @param key the key 180 * @param value the value 181 */ 182 public static void setFloat(String key, float value) { 183 NetworkTableEntry entry = m_table.getEntry(key); 184 entry.setDouble(value); 185 entry.setPersistent(); 186 } 187 188 /** 189 * Puts the given float into the preferences table if it doesn't already exist. 190 * 191 * @param key The key 192 * @param value The value 193 */ 194 public static void initFloat(String key, float value) { 195 NetworkTableEntry entry = m_table.getEntry(key); 196 entry.setDefaultDouble(value); 197 entry.setPersistent(); 198 } 199 200 /** 201 * Puts the given boolean into the preferences table. 202 * 203 * @param key the key 204 * @param value the value 205 */ 206 public static void setBoolean(String key, boolean value) { 207 NetworkTableEntry entry = m_table.getEntry(key); 208 entry.setBoolean(value); 209 entry.setPersistent(); 210 } 211 212 /** 213 * Puts the given boolean into the preferences table if it doesn't already exist. 214 * 215 * @param key The key 216 * @param value The value 217 */ 218 public static void initBoolean(String key, boolean value) { 219 NetworkTableEntry entry = m_table.getEntry(key); 220 entry.setDefaultBoolean(value); 221 entry.setPersistent(); 222 } 223 224 /** 225 * Puts the given long into the preferences table. 226 * 227 * @param key the key 228 * @param value the value 229 */ 230 public static void setLong(String key, long value) { 231 NetworkTableEntry entry = m_table.getEntry(key); 232 entry.setDouble(value); 233 entry.setPersistent(); 234 } 235 236 /** 237 * Puts the given long into the preferences table if it doesn't already exist. 238 * 239 * @param key The key 240 * @param value The value 241 */ 242 public static void initLong(String key, long value) { 243 NetworkTableEntry entry = m_table.getEntry(key); 244 entry.setDefaultDouble(value); 245 entry.setPersistent(); 246 } 247 248 /** 249 * Returns whether or not there is a key with the given name. 250 * 251 * @param key the key 252 * @return if there is a value at the given key 253 */ 254 public static boolean containsKey(String key) { 255 return m_table.containsKey(key); 256 } 257 258 /** 259 * Remove a preference. 260 * 261 * @param key the key 262 */ 263 public static void remove(String key) { 264 NetworkTableEntry entry = m_table.getEntry(key); 265 entry.clearPersistent(); 266 entry.unpublish(); 267 } 268 269 /** Remove all preferences. */ 270 public static void removeAll() { 271 for (String key : m_table.getKeys()) { 272 if (!".type".equals(key)) { 273 remove(key); 274 } 275 } 276 } 277 278 /** 279 * Returns the string at the given key. If this table does not have a value for that position, 280 * then the given backup value will be returned. 281 * 282 * @param key the key 283 * @param backup the value to return if none exists in the table 284 * @return either the value in the table, or the backup 285 */ 286 public static String getString(String key, String backup) { 287 return m_table.getEntry(key).getString(backup); 288 } 289 290 /** 291 * Returns the int at the given key. If this table does not have a value for that position, then 292 * the given backup value will be returned. 293 * 294 * @param key the key 295 * @param backup the value to return if none exists in the table 296 * @return either the value in the table, or the backup 297 */ 298 public static int getInt(String key, int backup) { 299 return (int) m_table.getEntry(key).getDouble(backup); 300 } 301 302 /** 303 * Returns the double at the given key. If this table does not have a value for that position, 304 * then the given backup value will be returned. 305 * 306 * @param key the key 307 * @param backup the value to return if none exists in the table 308 * @return either the value in the table, or the backup 309 */ 310 public static double getDouble(String key, double backup) { 311 return m_table.getEntry(key).getDouble(backup); 312 } 313 314 /** 315 * Returns the boolean at the given key. If this table does not have a value for that position, 316 * then the given backup value will be returned. 317 * 318 * @param key the key 319 * @param backup the value to return if none exists in the table 320 * @return either the value in the table, or the backup 321 */ 322 public static boolean getBoolean(String key, boolean backup) { 323 return m_table.getEntry(key).getBoolean(backup); 324 } 325 326 /** 327 * Returns the float at the given key. If this table does not have a value for that position, then 328 * the given backup value will be returned. 329 * 330 * @param key the key 331 * @param backup the value to return if none exists in the table 332 * @return either the value in the table, or the backup 333 */ 334 public static float getFloat(String key, float backup) { 335 return (float) m_table.getEntry(key).getDouble(backup); 336 } 337 338 /** 339 * Returns the long at the given key. If this table does not have a value for that position, then 340 * the given backup value will be returned. 341 * 342 * @param key the key 343 * @param backup the value to return if none exists in the table 344 * @return either the value in the table, or the backup 345 */ 346 public static long getLong(String key, long backup) { 347 return (long) m_table.getEntry(key).getDouble(backup); 348 } 349}