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.smartdashboard; 006 007import edu.wpi.first.hal.FRCNetComm.tResourceType; 008import edu.wpi.first.hal.HAL; 009import edu.wpi.first.networktables.NetworkTable; 010import edu.wpi.first.networktables.NetworkTableEntry; 011import edu.wpi.first.networktables.NetworkTableInstance; 012import edu.wpi.first.util.sendable.Sendable; 013import edu.wpi.first.util.sendable.SendableRegistry; 014import java.util.HashMap; 015import java.util.Map; 016import java.util.Set; 017 018/** 019 * The {@link SmartDashboard} class is the bridge between robot programs and the SmartDashboard on 020 * the laptop. 021 * 022 * <p>When a value is put into the SmartDashboard here, it pops up on the SmartDashboard on the 023 * laptop. Users can put values into and get values from the SmartDashboard. 024 */ 025public final class SmartDashboard { 026 /** The {@link NetworkTable} used by {@link SmartDashboard}. */ 027 private static NetworkTable table; 028 029 /** 030 * A table linking tables in the SmartDashboard to the {@link Sendable} objects they came from. 031 */ 032 @SuppressWarnings("PMD.UseConcurrentHashMap") 033 private static final Map<String, Sendable> tablesToData = new HashMap<>(); 034 035 /** The executor for listener tasks; calls listener tasks synchronously from main thread. */ 036 private static final ListenerExecutor listenerExecutor = new ListenerExecutor(); 037 038 static { 039 setNetworkTableInstance(NetworkTableInstance.getDefault()); 040 HAL.report(tResourceType.kResourceType_SmartDashboard, 0); 041 } 042 043 private SmartDashboard() { 044 throw new UnsupportedOperationException("This is a utility class!"); 045 } 046 047 /** 048 * Set the NetworkTable instance used for entries. For testing purposes; use with caution. 049 * 050 * @param inst NetworkTable instance 051 */ 052 public static synchronized void setNetworkTableInstance(NetworkTableInstance inst) { 053 SmartDashboard.table = inst.getTable("SmartDashboard"); 054 tablesToData.clear(); 055 } 056 057 /** 058 * Maps the specified key to the specified value in this table. The key can not be null. The value 059 * can be retrieved by calling the get method with a key that is equal to the original key. 060 * 061 * @param key the key 062 * @param data the value 063 * @throws IllegalArgumentException If key is null 064 */ 065 @SuppressWarnings("PMD.CompareObjectsWithEquals") 066 public static synchronized void putData(String key, Sendable data) { 067 Sendable sddata = tablesToData.get(key); 068 if (sddata == null || sddata != data) { 069 tablesToData.put(key, data); 070 NetworkTable dataTable = table.getSubTable(key); 071 SendableBuilderImpl builder = new SendableBuilderImpl(); 072 builder.setTable(dataTable); 073 SendableRegistry.publish(data, builder); 074 builder.startListeners(); 075 dataTable.getEntry(".name").setString(key); 076 } 077 } 078 079 /** 080 * Maps the specified key (where the key is the name of the {@link Sendable}) to the specified 081 * value in this table. The value can be retrieved by calling the get method with a key that is 082 * equal to the original key. 083 * 084 * @param value the value 085 * @throws IllegalArgumentException If key is null 086 */ 087 public static void putData(Sendable value) { 088 String name = SendableRegistry.getName(value); 089 if (!name.isEmpty()) { 090 putData(name, value); 091 } 092 } 093 094 /** 095 * Returns the value at the specified key. 096 * 097 * @param key the key 098 * @return the value 099 * @throws IllegalArgumentException if the key is null 100 */ 101 public static synchronized Sendable getData(String key) { 102 Sendable data = tablesToData.get(key); 103 if (data == null) { 104 throw new IllegalArgumentException("SmartDashboard data does not exist: " + key); 105 } else { 106 return data; 107 } 108 } 109 110 /** 111 * Gets the entry for the specified key. 112 * 113 * @param key the key name 114 * @return Network table entry. 115 */ 116 public static NetworkTableEntry getEntry(String key) { 117 return table.getEntry(key); 118 } 119 120 /** 121 * Checks the table and tells if it contains the specified key. 122 * 123 * @param key the key to search for 124 * @return true if the table as a value assigned to the given key 125 */ 126 public static boolean containsKey(String key) { 127 return table.containsKey(key); 128 } 129 130 /** 131 * Get the keys stored in the SmartDashboard table of NetworkTables. 132 * 133 * @param types bitmask of types; 0 is treated as a "don't care". 134 * @return keys currently in the table 135 */ 136 public static Set<String> getKeys(int types) { 137 return table.getKeys(types); 138 } 139 140 /** 141 * Get the keys stored in the SmartDashboard table of NetworkTables. 142 * 143 * @return keys currently in the table. 144 */ 145 public static Set<String> getKeys() { 146 return table.getKeys(); 147 } 148 149 /** 150 * Makes a key's value persistent through program restarts. The key cannot be null. 151 * 152 * @param key the key name 153 */ 154 public static void setPersistent(String key) { 155 getEntry(key).setPersistent(); 156 } 157 158 /** 159 * Stop making a key's value persistent through program restarts. The key cannot be null. 160 * 161 * @param key the key name 162 */ 163 public static void clearPersistent(String key) { 164 getEntry(key).clearPersistent(); 165 } 166 167 /** 168 * Returns whether the value is persistent through program restarts. The key cannot be null. 169 * 170 * @param key the key name 171 * @return True if the value is persistent. 172 */ 173 public static boolean isPersistent(String key) { 174 return getEntry(key).isPersistent(); 175 } 176 177 /** 178 * Put a boolean in the table. 179 * 180 * @param key the key to be assigned to 181 * @param value the value that will be assigned 182 * @return False if the table key already exists with a different type 183 */ 184 public static boolean putBoolean(String key, boolean value) { 185 return getEntry(key).setBoolean(value); 186 } 187 188 /** 189 * Gets the current value in the table, setting it if it does not exist. 190 * 191 * @param key the key 192 * @param defaultValue the default value to set if key does not exist. 193 * @return False if the table key exists with a different type 194 */ 195 public static boolean setDefaultBoolean(String key, boolean defaultValue) { 196 return getEntry(key).setDefaultBoolean(defaultValue); 197 } 198 199 /** 200 * Returns the boolean the key maps to. If the key does not exist or is of different type, it will 201 * return the default value. 202 * 203 * @param key the key to look up 204 * @param defaultValue the value to be returned if no value is found 205 * @return the value associated with the given key or the given default value if there is no value 206 * associated with the key 207 */ 208 public static boolean getBoolean(String key, boolean defaultValue) { 209 return getEntry(key).getBoolean(defaultValue); 210 } 211 212 /** 213 * Put a number in the table. 214 * 215 * @param key the key to be assigned to 216 * @param value the value that will be assigned 217 * @return False if the table key already exists with a different type 218 */ 219 public static boolean putNumber(String key, double value) { 220 return getEntry(key).setDouble(value); 221 } 222 223 /** 224 * Gets the current value in the table, setting it if it does not exist. 225 * 226 * @param key the key 227 * @param defaultValue the default value to set if key does not exist. 228 * @return False if the table key exists with a different type 229 */ 230 public static boolean setDefaultNumber(String key, double defaultValue) { 231 return getEntry(key).setDefaultDouble(defaultValue); 232 } 233 234 /** 235 * Returns the number the key maps to. If the key does not exist or is of different type, it will 236 * return the default value. 237 * 238 * @param key the key to look up 239 * @param defaultValue the value to be returned if no value is found 240 * @return the value associated with the given key or the given default value if there is no value 241 * associated with the key 242 */ 243 public static double getNumber(String key, double defaultValue) { 244 return getEntry(key).getDouble(defaultValue); 245 } 246 247 /** 248 * Put a string in the table. 249 * 250 * @param key the key to be assigned to 251 * @param value the value that will be assigned 252 * @return False if the table key already exists with a different type 253 */ 254 public static boolean putString(String key, String value) { 255 return getEntry(key).setString(value); 256 } 257 258 /** 259 * Gets the current value in the table, setting it if it does not exist. 260 * 261 * @param key the key 262 * @param defaultValue the default value to set if key does not exist. 263 * @return False if the table key exists with a different type 264 */ 265 public static boolean setDefaultString(String key, String defaultValue) { 266 return getEntry(key).setDefaultString(defaultValue); 267 } 268 269 /** 270 * Returns the string the key maps to. If the key does not exist or is of different type, it will 271 * return the default value. 272 * 273 * @param key the key to look up 274 * @param defaultValue the value to be returned if no value is found 275 * @return the value associated with the given key or the given default value if there is no value 276 * associated with the key 277 */ 278 public static String getString(String key, String defaultValue) { 279 return getEntry(key).getString(defaultValue); 280 } 281 282 /** 283 * Put a boolean array in the table. 284 * 285 * @param key the key to be assigned to 286 * @param value the value that will be assigned 287 * @return False if the table key already exists with a different type 288 */ 289 public static boolean putBooleanArray(String key, boolean[] value) { 290 return getEntry(key).setBooleanArray(value); 291 } 292 293 /** 294 * Put a boolean array in the table. 295 * 296 * @param key the key to be assigned to 297 * @param value the value that will be assigned 298 * @return False if the table key already exists with a different type 299 */ 300 public static boolean putBooleanArray(String key, Boolean[] value) { 301 return getEntry(key).setBooleanArray(value); 302 } 303 304 /** 305 * Gets the current value in the table, setting it if it does not exist. 306 * 307 * @param key the key 308 * @param defaultValue the default value to set if key does not exist. 309 * @return False if the table key exists with a different type 310 */ 311 public static boolean setDefaultBooleanArray(String key, boolean[] defaultValue) { 312 return getEntry(key).setDefaultBooleanArray(defaultValue); 313 } 314 315 /** 316 * Gets the current value in the table, setting it if it does not exist. 317 * 318 * @param key the key 319 * @param defaultValue the default value to set if key does not exist. 320 * @return False if the table key exists with a different type 321 */ 322 public static boolean setDefaultBooleanArray(String key, Boolean[] defaultValue) { 323 return getEntry(key).setDefaultBooleanArray(defaultValue); 324 } 325 326 /** 327 * Returns the boolean array the key maps to. If the key does not exist or is of different type, 328 * it will return the default value. 329 * 330 * @param key the key to look up 331 * @param defaultValue the value to be returned if no value is found 332 * @return the value associated with the given key or the given default value if there is no value 333 * associated with the key 334 */ 335 public static boolean[] getBooleanArray(String key, boolean[] defaultValue) { 336 return getEntry(key).getBooleanArray(defaultValue); 337 } 338 339 /** 340 * Returns the boolean array the key maps to. If the key does not exist or is of different type, 341 * it will return the default value. 342 * 343 * @param key the key to look up 344 * @param defaultValue the value to be returned if no value is found 345 * @return the value associated with the given key or the given default value if there is no value 346 * associated with the key 347 */ 348 public static Boolean[] getBooleanArray(String key, Boolean[] defaultValue) { 349 return getEntry(key).getBooleanArray(defaultValue); 350 } 351 352 /** 353 * Put a number array in the table. 354 * 355 * @param key the key to be assigned to 356 * @param value the value that will be assigned 357 * @return False if the table key already exists with a different type 358 */ 359 public static boolean putNumberArray(String key, double[] value) { 360 return getEntry(key).setDoubleArray(value); 361 } 362 363 /** 364 * Put a number array in the table. 365 * 366 * @param key the key to be assigned to 367 * @param value the value that will be assigned 368 * @return False if the table key already exists with a different type 369 */ 370 public static boolean putNumberArray(String key, Double[] value) { 371 return getEntry(key).setNumberArray(value); 372 } 373 374 /** 375 * Gets the current value in the table, setting it if it does not exist. 376 * 377 * @param key the key 378 * @param defaultValue the default value to set if key does not exist. 379 * @return False if the table key exists with a different type 380 */ 381 public static boolean setDefaultNumberArray(String key, double[] defaultValue) { 382 return getEntry(key).setDefaultDoubleArray(defaultValue); 383 } 384 385 /** 386 * Gets the current value in the table, setting it if it does not exist. 387 * 388 * @param key the key 389 * @param defaultValue the default value to set if key does not exist. 390 * @return False if the table key exists with a different type 391 */ 392 public static boolean setDefaultNumberArray(String key, Double[] defaultValue) { 393 return getEntry(key).setDefaultNumberArray(defaultValue); 394 } 395 396 /** 397 * Returns the number array the key maps to. If the key does not exist or is of different type, it 398 * will return the default value. 399 * 400 * @param key the key to look up 401 * @param defaultValue the value to be returned if no value is found 402 * @return the value associated with the given key or the given default value if there is no value 403 * associated with the key 404 */ 405 public static double[] getNumberArray(String key, double[] defaultValue) { 406 return getEntry(key).getDoubleArray(defaultValue); 407 } 408 409 /** 410 * Returns the number array the key maps to. If the key does not exist or is of different type, it 411 * will return the default value. 412 * 413 * @param key the key to look up 414 * @param defaultValue the value to be returned if no value is found 415 * @return the value associated with the given key or the given default value if there is no value 416 * associated with the key 417 */ 418 public static Double[] getNumberArray(String key, Double[] defaultValue) { 419 return getEntry(key).getDoubleArray(defaultValue); 420 } 421 422 /** 423 * Put a string array in the table. 424 * 425 * @param key the key to be assigned to 426 * @param value the value that will be assigned 427 * @return False if the table key already exists with a different type 428 */ 429 public static boolean putStringArray(String key, String[] value) { 430 return getEntry(key).setStringArray(value); 431 } 432 433 /** 434 * Gets the current value in the table, setting it if it does not exist. 435 * 436 * @param key the key 437 * @param defaultValue the default value to set if key does not exist. 438 * @return False if the table key exists with a different type 439 */ 440 public static boolean setDefaultStringArray(String key, String[] defaultValue) { 441 return getEntry(key).setDefaultStringArray(defaultValue); 442 } 443 444 /** 445 * Returns the string array the key maps to. If the key does not exist or is of different type, it 446 * will return the default value. 447 * 448 * @param key the key to look up 449 * @param defaultValue the value to be returned if no value is found 450 * @return the value associated with the given key or the given default value if there is no value 451 * associated with the key 452 */ 453 public static String[] getStringArray(String key, String[] defaultValue) { 454 return getEntry(key).getStringArray(defaultValue); 455 } 456 457 /** 458 * Put a raw value (byte array) in the table. 459 * 460 * @param key the key to be assigned to 461 * @param value the value that will be assigned 462 * @return False if the table key already exists with a different type 463 */ 464 public static boolean putRaw(String key, byte[] value) { 465 return getEntry(key).setRaw(value); 466 } 467 468 /** 469 * Gets the current value in the table, setting it if it does not exist. 470 * 471 * @param key the key 472 * @param defaultValue the default value to set if key does not exist. 473 * @return False if the table key exists with a different type 474 */ 475 public static boolean setDefaultRaw(String key, byte[] defaultValue) { 476 return getEntry(key).setDefaultRaw(defaultValue); 477 } 478 479 /** 480 * Returns the raw value (byte array) the key maps to. If the key does not exist or is of 481 * different type, it will return the default value. 482 * 483 * @param key the key to look up 484 * @param defaultValue the value to be returned if no value is found 485 * @return the value associated with the given key or the given default value if there is no value 486 * associated with the key 487 */ 488 public static byte[] getRaw(String key, byte[] defaultValue) { 489 return getEntry(key).getRaw(defaultValue); 490 } 491 492 /** 493 * Posts a task from a listener to the ListenerExecutor, so that it can be run synchronously from 494 * the main loop on the next call to {@link SmartDashboard#updateValues()}. 495 * 496 * @param task The task to run synchronously from the main thread. 497 */ 498 public static void postListenerTask(Runnable task) { 499 listenerExecutor.execute(task); 500 } 501 502 /** Puts all sendable data to the dashboard. */ 503 public static synchronized void updateValues() { 504 // Execute posted listener tasks 505 listenerExecutor.runListenerTasks(); 506 for (Sendable data : tablesToData.values()) { 507 SendableRegistry.update(data); 508 } 509 } 510}