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