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 preferences keys. 102 * 103 * @return a collection of the keys 104 */ 105 public static Collection<String> getKeys() { 106 return m_table.getKeys(); 107 } 108 109 /** 110 * Puts the given string into the preferences table. 111 * 112 * @param key the key 113 * @param value the value 114 * @throws NullPointerException if value is null 115 */ 116 public static void setString(String key, String value) { 117 requireNonNullParam(value, "value", "setString"); 118 119 NetworkTableEntry entry = m_table.getEntry(key); 120 entry.setString(value); 121 entry.setPersistent(); 122 } 123 124 /** 125 * Puts the given string into the preferences table if it doesn't already exist. 126 * 127 * @param key The key 128 * @param value The value 129 */ 130 public static void initString(String key, String value) { 131 NetworkTableEntry entry = m_table.getEntry(key); 132 entry.setDefaultString(value); 133 entry.setPersistent(); 134 } 135 136 /** 137 * Puts the given int into the preferences table. 138 * 139 * @param key the key 140 * @param value the value 141 */ 142 public static void setInt(String key, int value) { 143 NetworkTableEntry entry = m_table.getEntry(key); 144 entry.setDouble(value); 145 entry.setPersistent(); 146 } 147 148 /** 149 * Puts the given int into the preferences table if it doesn't already exist. 150 * 151 * @param key The key 152 * @param value The value 153 */ 154 public static void initInt(String key, int value) { 155 NetworkTableEntry entry = m_table.getEntry(key); 156 entry.setDefaultDouble(value); 157 entry.setPersistent(); 158 } 159 160 /** 161 * Puts the given double into the preferences table. 162 * 163 * @param key the key 164 * @param value the value 165 */ 166 public static void setDouble(String key, double value) { 167 NetworkTableEntry entry = m_table.getEntry(key); 168 entry.setDouble(value); 169 entry.setPersistent(); 170 } 171 172 /** 173 * Puts the given double into the preferences table if it doesn't already exist. 174 * 175 * @param key The key 176 * @param value The value 177 */ 178 public static void initDouble(String key, double value) { 179 NetworkTableEntry entry = m_table.getEntry(key); 180 entry.setDefaultDouble(value); 181 entry.setPersistent(); 182 } 183 184 /** 185 * Puts the given float into the preferences table. 186 * 187 * @param key the key 188 * @param value the value 189 */ 190 public static void setFloat(String key, float value) { 191 NetworkTableEntry entry = m_table.getEntry(key); 192 entry.setDouble(value); 193 entry.setPersistent(); 194 } 195 196 /** 197 * Puts the given float into the preferences table if it doesn't already exist. 198 * 199 * @param key The key 200 * @param value The value 201 */ 202 public static void initFloat(String key, float value) { 203 NetworkTableEntry entry = m_table.getEntry(key); 204 entry.setDefaultDouble(value); 205 entry.setPersistent(); 206 } 207 208 /** 209 * Puts the given boolean into the preferences table. 210 * 211 * @param key the key 212 * @param value the value 213 */ 214 public static void setBoolean(String key, boolean value) { 215 NetworkTableEntry entry = m_table.getEntry(key); 216 entry.setBoolean(value); 217 entry.setPersistent(); 218 } 219 220 /** 221 * Puts the given boolean into the preferences table if it doesn't already exist. 222 * 223 * @param key The key 224 * @param value The value 225 */ 226 public static void initBoolean(String key, boolean value) { 227 NetworkTableEntry entry = m_table.getEntry(key); 228 entry.setDefaultBoolean(value); 229 entry.setPersistent(); 230 } 231 232 /** 233 * Puts the given long into the preferences table. 234 * 235 * @param key the key 236 * @param value the value 237 */ 238 public static void setLong(String key, long value) { 239 NetworkTableEntry entry = m_table.getEntry(key); 240 entry.setInteger(value); 241 entry.setPersistent(); 242 } 243 244 /** 245 * Puts the given long into the preferences table if it doesn't already exist. 246 * 247 * @param key The key 248 * @param value The value 249 */ 250 public static void initLong(String key, long value) { 251 NetworkTableEntry entry = m_table.getEntry(key); 252 entry.setDefaultInteger(value); 253 entry.setPersistent(); 254 } 255 256 /** 257 * Returns whether there is a key with the given name. 258 * 259 * @param key the key 260 * @return if there is a value at the given key 261 */ 262 public static boolean containsKey(String key) { 263 return m_table.containsKey(key); 264 } 265 266 /** 267 * Remove a preference. 268 * 269 * @param key the key 270 */ 271 public static void remove(String key) { 272 NetworkTableEntry entry = m_table.getEntry(key); 273 entry.clearPersistent(); 274 entry.unpublish(); 275 } 276 277 /** Remove all preferences. */ 278 public static void removeAll() { 279 for (String key : m_table.getKeys()) { 280 if (!".type".equals(key)) { 281 remove(key); 282 } 283 } 284 } 285 286 /** 287 * Returns the string at the given key. If this table does not have a value for that position, 288 * then the given backup value will be returned. 289 * 290 * @param key the key 291 * @param backup the value to return if none exists in the table 292 * @return either the value in the table, or the backup 293 */ 294 public static String getString(String key, String backup) { 295 return m_table.getEntry(key).getString(backup); 296 } 297 298 /** 299 * Returns the int at the given key. If this table does not have a value for that position, then 300 * the given backup value will be returned. 301 * 302 * @param key the key 303 * @param backup the value to return if none exists in the table 304 * @return either the value in the table, or the backup 305 */ 306 public static int getInt(String key, int backup) { 307 return (int) m_table.getEntry(key).getDouble(backup); 308 } 309 310 /** 311 * Returns the double at the given key. If this table does not have a value for that position, 312 * then the given backup value will be returned. 313 * 314 * @param key the key 315 * @param backup the value to return if none exists in the table 316 * @return either the value in the table, or the backup 317 */ 318 public static double getDouble(String key, double backup) { 319 return m_table.getEntry(key).getDouble(backup); 320 } 321 322 /** 323 * Returns the boolean at the given key. If this table does not have a value for that position, 324 * then the given backup value will be returned. 325 * 326 * @param key the key 327 * @param backup the value to return if none exists in the table 328 * @return either the value in the table, or the backup 329 */ 330 public static boolean getBoolean(String key, boolean backup) { 331 return m_table.getEntry(key).getBoolean(backup); 332 } 333 334 /** 335 * Returns the float at the given key. If this table does not have a value for that position, then 336 * the given backup value will be returned. 337 * 338 * @param key the key 339 * @param backup the value to return if none exists in the table 340 * @return either the value in the table, or the backup 341 */ 342 public static float getFloat(String key, float backup) { 343 return (float) m_table.getEntry(key).getDouble(backup); 344 } 345 346 /** 347 * Returns the long at the given key. If this table does not have a value for that position, then 348 * the given backup value will be returned. 349 * 350 * @param key the key 351 * @param backup the value to return if none exists in the table 352 * @return either the value in the table, or the backup 353 */ 354 public static long getLong(String key, long backup) { 355 return m_table.getEntry(key).getInteger(backup); 356 } 357}