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