Skip to content

Commit f46e5be

Browse files
Added LiveWindow, DashboardBundle, ActuatorSendable
1 parent 7d81460 commit f46e5be

23 files changed

+270
-16
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# abstract-dashboard
2+
An abstraction of NetworkTables, Shuffleboard, SmartDashboard, and LiveWindow
3+
4+
### TODO
5+
* Have master object to hold instances of important stuff

core/src/main/java/com/first1444/dashboard/ActiveComponent.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,21 @@ interface ActiveComponent {
1515
override fun onRemove() {
1616
}
1717
}
18+
@JvmStatic
19+
fun create(title: String, update: Runnable): ActiveComponent {
20+
return object : ActiveComponent {
21+
override val title: String = title
22+
23+
override fun update() {
24+
update.run()
25+
}
26+
override fun onRemove() {
27+
}
28+
}
29+
}
30+
@JvmSynthetic
31+
fun create(title: String, update: () -> Unit): ActiveComponent {
32+
return create(title, Runnable(update))
33+
}
1834
}
1935
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.first1444.dashboard.advanced
2+
3+
import com.first1444.dashboard.ActiveComponent
4+
import com.first1444.dashboard.BasicDashboard
5+
import com.first1444.dashboard.enable.EnabledProvider
6+
7+
class ActuatorSendable(
8+
private val sendable: Sendable<*>,
9+
private val enabledProvider: EnabledProvider,
10+
private val reportActuator: Boolean
11+
) : Sendable<ActiveComponent> {
12+
override fun init(title: String, dashboard: BasicDashboard): ActiveComponent {
13+
if(reportActuator){
14+
SendableHelper(dashboard).setActuator(true)
15+
}
16+
return object : ActiveComponent {
17+
override val title: String get() = title
18+
19+
private var activeComponent: ActiveComponent? = null
20+
21+
override fun update() {
22+
var activeComponent = this.activeComponent
23+
if(enabledProvider.isEnabled){
24+
if(activeComponent == null){
25+
activeComponent = sendable.init(title, dashboard)
26+
this.activeComponent = activeComponent
27+
}
28+
activeComponent.update()
29+
} else {
30+
if(activeComponent != null){
31+
activeComponent.onRemove()
32+
this.activeComponent = null
33+
}
34+
}
35+
}
36+
37+
override fun onRemove() {
38+
activeComponent?.onRemove()
39+
activeComponent = null
40+
}
41+
42+
}
43+
}
44+
}
45+

core/src/main/java/com/first1444/dashboard/advanced/AdvancedDashboard.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.first1444.dashboard.ActiveComponent
44

55
interface AdvancedDashboard {
66
fun delete(key: String): Boolean
7+
fun delete(activeComponent: ActiveComponent): Boolean
78

89
fun <T : ActiveComponent>add(key: String, data: Sendable<T>): T
910
}

core/src/main/java/com/first1444/dashboard/advanced/BasicAdvancedDashboard.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ class BasicAdvancedDashboard(
2020
return componentMap.remove(key) != null
2121
}
2222

23+
override fun delete(activeComponent: ActiveComponent): Boolean {
24+
val iterator = componentMap.iterator()
25+
while(iterator.hasNext()){
26+
val (name, component) = iterator.next()
27+
if(component == activeComponent){
28+
basicDashboard.delete(name)
29+
activeComponent.onRemove()
30+
iterator.remove()
31+
return true
32+
}
33+
}
34+
return false
35+
}
36+
2337
override fun update() {
2438
for(component in componentMap.values){
2539
component.update()

core/src/main/java/com/first1444/dashboard/advanced/Sendable.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import com.first1444.dashboard.BasicDashboard
55

66
interface Sendable<out T : ActiveComponent> {
77
/**
8+
* It is possible that [dashboard] will already have some of its properties filled in. This may be because of persistent data
9+
* or because of this instance being wrapped in a class such as [ActuatorSendable] which will call [ActiveComponent.onRemove] on the returned
10+
* [ActiveComponent] when temporarily stopping updates to the data that this [Sendable] represents
11+
*
12+
* The caller is responsible for creating [dashboard] and is responsible for removing [dashboard] after [ActiveComponent.onRemove] is called, if the caller wants to.
813
* @param title The title. [ActiveComponent.title] should be set to this
914
* @param dashboard The dashboard to apply properties to
1015
* @return An [ActiveComponent] that will be updated and eventually removed

core/src/main/java/com/first1444/dashboard/advanced/SendableBuilder.kt

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.first1444.dashboard.advanced
2+
3+
interface SendableDashboard {
4+
5+
fun delete(key: String): Boolean
6+
fun delete(sendable: Sendable<*>): Boolean
7+
8+
fun add(key: String, data: Sendable<*>)
9+
}

core/src/main/java/com/first1444/dashboard/advanced/SendableHelper.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ open class SendableHelper(
4343
get() = dashboard[".controllable"].getter.getBoolean(false)
4444
set(value) { dashboard[".controllable"].strictSetter.setBoolean(value) }
4545

46+
/**
47+
* This is primarily used for actuators. It is not clearly defined what Shuffleboard, SmartDashboard, or LiveWindow components use this but it is
48+
* not necessary to set this for every component. The general rule is that if it's an actuator, set this to true when it can be controlled, set it to false
49+
* when you stop checking for new control input.
50+
*/
4651
fun setControllable(value: Boolean): SendableHelper {
4752
isControllable = value
4853
return this
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.first1444.dashboard.bundle
2+
3+
import com.first1444.dashboard.ActiveComponent
4+
5+
interface ActiveDashboardBundle : DashboardBundle, ActiveComponent
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.first1444.dashboard.bundle
2+
3+
import com.first1444.dashboard.BasicDashboard
4+
import com.first1444.dashboard.advanced.AdvancedDashboard
5+
import com.first1444.dashboard.livewindow.LiveWindow
6+
import com.first1444.dashboard.shuffleboard.Shuffleboard
7+
8+
interface DashboardBundle {
9+
val rootDashboard: BasicDashboard
10+
11+
val shuffleboard: Shuffleboard
12+
13+
val smartDashboard: AdvancedDashboard
14+
val smartDashboardBasic: BasicDashboard
15+
16+
val liveWindow: LiveWindow
17+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.first1444.dashboard.bundle
2+
3+
import com.first1444.dashboard.BasicDashboard
4+
import com.first1444.dashboard.advanced.AdvancedDashboard
5+
import com.first1444.dashboard.advanced.BasicAdvancedDashboard
6+
import com.first1444.dashboard.livewindow.DefaultLiveWindow
7+
import com.first1444.dashboard.livewindow.LiveWindow
8+
import com.first1444.dashboard.shuffleboard.implementations.DefaultShuffleboard
9+
10+
class DefaultDashboardBundle(
11+
override val rootDashboard: BasicDashboard
12+
) : ActiveDashboardBundle {
13+
override val title: String = "Default Dashboard Bundle"
14+
15+
override val shuffleboard = DefaultShuffleboard(rootDashboard)
16+
17+
override val smartDashboardBasic: BasicDashboard = rootDashboard.getSubDashboard("SmartDashboard")
18+
override val smartDashboard = BasicAdvancedDashboard("Smart Dashboard", smartDashboardBasic)
19+
20+
override val liveWindow: LiveWindow = DefaultLiveWindow(rootDashboard)
21+
22+
override fun update() {
23+
shuffleboard.update()
24+
smartDashboard.update()
25+
}
26+
27+
override fun onRemove() {
28+
shuffleboard.onRemove()
29+
smartDashboard.onRemove()
30+
}
31+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.first1444.dashboard.enable
2+
3+
interface EnabledProvider {
4+
val isEnabled: Boolean
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.first1444.dashboard.enable
2+
3+
interface MutableEnabledProvider : EnabledProvider {
4+
override var isEnabled: Boolean
5+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.first1444.dashboard.enable
2+
3+
class SimpleEnabledProvider
4+
@JvmOverloads constructor(
5+
startEnabled: Boolean = false
6+
) : MutableEnabledProvider {
7+
@Volatile // Just add some thread safety because why not.
8+
override var isEnabled: Boolean = startEnabled
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.first1444.dashboard.livewindow
2+
3+
import com.first1444.dashboard.ActiveComponent
4+
5+
interface ActiveLiveWindow : LiveWindow, ActiveComponent
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.first1444.dashboard.livewindow
2+
3+
import com.first1444.dashboard.BasicDashboard
4+
import com.first1444.dashboard.advanced.SendableDashboard
5+
6+
class DefaultLiveWindow(
7+
rootDashboard: BasicDashboard
8+
) : ActiveLiveWindow {
9+
private val dashboard = rootDashboard.getSubDashboard("LiveWindow")
10+
private val statusDashboard = dashboard.getSubDashboard(".status")
11+
private val enabledEntry = statusDashboard["LW Enabled"]
12+
13+
override var isEnabled: Boolean = false
14+
set(value) {
15+
field = value
16+
enabledEntry.strictSetter.setBoolean(value)
17+
}
18+
override val sendableDashboard: SendableDashboard
19+
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
20+
21+
override val title: String = "Live Window"
22+
23+
override fun update() {
24+
}
25+
26+
override fun onRemove() {
27+
}
28+
29+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.first1444.dashboard.livewindow
2+
3+
import com.first1444.dashboard.advanced.SendableDashboard
4+
import com.first1444.dashboard.enable.MutableEnabledProvider
5+
6+
interface LiveWindow : MutableEnabledProvider {
7+
/*
8+
The design of the WPI LiveWindow API: The live window can be enabled and disabled. In IterativeRobotBase, LiveWindow is
9+
enabled only when going into test mode and disabled at every other possible time. Although it can be disabled,
10+
telemetry can override this for certain Sendable objects.
11+
*/
12+
13+
val sendableDashboard: SendableDashboard
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.first1444.dashboard.shuffleboard
2+
3+
import com.first1444.dashboard.ActiveComponent
4+
import com.first1444.dashboard.BasicDashboard
5+
import com.first1444.dashboard.value.ValueProperty
6+
import com.first1444.dashboard.value.implementations.PropertyActiveComponent
7+
8+
class PropertyComponent(
9+
private val valueProperty: ValueProperty
10+
) : ShuffleboardComponent<ActiveComponent> {
11+
override fun init(title: String, parentDashboard: BasicDashboard, metadataDashboard: BasicDashboard): ActiveComponent {
12+
val entry = parentDashboard[title]
13+
return PropertyActiveComponent(title, entry, valueProperty)
14+
}
15+
}

core/src/main/java/com/first1444/dashboard/shuffleboard/implementations/DefaultShuffleboardContainer.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ class DefaultShuffleboardContainer(
2828
return remove(key)
2929
}
3030

31+
override fun delete(activeComponent: ActiveComponent): Boolean {
32+
return remove(activeComponent)
33+
}
34+
3135
override fun <T : ActiveComponent> add(key: String, data: Sendable<T>): T {
32-
val component = SendableComponent(data)
33-
return component.init(key, dashboard, metadataDashboard)
36+
return add(key, SendableComponent(data))
3437
}
3538

3639
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.first1444.dashboard.shuffleboard.implementations
2+
3+
import com.first1444.dashboard.BasicDashboard
4+
5+
class GyroMetadataHelper(
6+
private val metadataDashboard: BasicDashboard
7+
) {
8+
private val propertiesDashboard: BasicDashboard get() = metadataDashboard.getSubDashboard("Properties")
9+
fun setMajorTickSpacing(majorTickSpacing: Double): GyroMetadataHelper {
10+
propertiesDashboard["Major tick spacing"].strictSetter.setDouble(majorTickSpacing)
11+
return this
12+
}
13+
fun setStartingAngle(startingAngleDegrees: Double): GyroMetadataHelper {
14+
propertiesDashboard["Starting angle"].strictSetter.setDouble(startingAngleDegrees)
15+
return this
16+
}
17+
18+
/**
19+
* Only works on early 2020-beta Shuffleboard versions and all versions after 2020
20+
* @param isCounterClockwise true to set the gyro to be counter clockwise, false for clockwise
21+
*/
22+
fun setCounterClockwise(isCounterClockwise: Boolean): GyroMetadataHelper {
23+
propertiesDashboard["Counter clockwise"].strictSetter.setBoolean(isCounterClockwise)
24+
return this
25+
}
26+
}

wpi/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
dependencies {
33
api "edu.wpi.first.ntcore:ntcore-java:$wpiLibVersion"
44
implementation "edu.wpi.first.ntcore:ntcore-jni:$wpiLibVersion"
5-
implementation "edu.wpi.first.ntcore:ntcore-jni:$wpiLibVersion:linuxx86-64"
5+
// implementation "edu.wpi.first.ntcore:ntcore-jni:$wpiLibVersion:linuxx86-64"
66
}

wpi/src/main/java/com/first1444/dashboard/wpi/VideoSourceSendable.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import com.first1444.dashboard.advanced.Sendable
77
class VideoSourceSendable(
88
private val uri: String
99
) : Sendable<ActiveComponent> {
10+
companion object {
11+
const val CAMERA_SERVER_PROTOCOL = "camera_server://"
12+
}
1013
override fun init(title: String, dashboard: BasicDashboard): ActiveComponent {
1114
dashboard[".ShuffleboardURI"].strictSetter.setString(uri)
1215
return ActiveComponent.createTitleOnly(title)

0 commit comments

Comments
 (0)