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