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