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