Skip to content

Commit b924e71

Browse files
authored
feat: FateWeaver extension (#5)
* add: include Fateweaver extension and update project settings for it Signed-off-by: Zach Harel <zach@zharel.me> * add: implement FateComponent for FateWeaver integration and telemetry logging Signed-off-by: Zach Harel <zach@zharel.me> --------- Signed-off-by: Zach Harel <zach@zharel.me>
1 parent fa21094 commit b924e71

5 files changed

Lines changed: 234 additions & 2 deletions

File tree

fateweaver/build.gradle.kts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
plugins {
2+
kotlin("android")
3+
id("com.android.library")
4+
}
5+
6+
android {
7+
namespace = "dev.nextftc.extensions.fateweaver"
8+
compileSdk = 35
9+
10+
defaultConfig {
11+
minSdk = 24
12+
}
13+
14+
compileOptions {
15+
sourceCompatibility = JavaVersion.VERSION_1_8
16+
targetCompatibility = JavaVersion.VERSION_1_8
17+
}
18+
19+
kotlinOptions {
20+
jvmTarget = "1.8"
21+
freeCompilerArgs += "-Xjvm-default=all"
22+
}
23+
24+
publishing {
25+
singleVariant("release")
26+
}
27+
}
28+
29+
dependencies {
30+
implementation(libs.bundles.nextftc)
31+
implementation(libs.bundles.ftc)
32+
implementation(libs.fateweaver)
33+
}
34+
35+
description =
36+
"Support for using FateWeaver with NextFTC."
37+
38+
nextFTCPublishing {
39+
displayName = "NextFTC Extensions - FateWeaver"
40+
logoPath = "../assets/logo-icon.svg"
41+
version = property("versions.fateweaver") as String
42+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package dev.nextftc.extensions.fateweaver
2+
3+
import dev.nextftc.core.commands.CommandManager
4+
import dev.nextftc.core.components.Component
5+
import gay.zharel.fateweaver.flight.FlightLogChannel
6+
import gay.zharel.fateweaver.flight.FlightRecorder
7+
import gay.zharel.fateweaver.log.LogChannel
8+
import gay.zharel.fateweaver.schemas.FateSchema
9+
import java.util.function.Supplier
10+
import kotlin.reflect.KClass
11+
12+
/**
13+
* FateWeaver integration component for NextFTC.
14+
*
15+
* This component provides a high-level interface for logging telemetry data using FateWeaver's
16+
* flight recorder system.
17+
* It manages log channels, handles periodic data publishing, and
18+
* automatically captures command snapshots during robot operation.
19+
*
20+
* Most FateComponent calls forward to [FlightRecorder].
21+
*
22+
* @see FlightRecorder
23+
*/
24+
object FateComponent : Component {
25+
/**
26+
* Internal channel used to log command manager snapshots.
27+
*/
28+
private lateinit var snapshotChannel: FlightLogChannel<Array<String>>
29+
30+
/**
31+
* Map of registered publishers that will be automatically invoked during periodic updates.
32+
* Each publisher supplies data to its associated log channel.
33+
*/
34+
private val registeredPublishers: MutableMap<LogChannel<Any>, Supplier<Any>> = mutableMapOf()
35+
36+
/**
37+
* Creates a new log channel with a custom schema.
38+
*
39+
* Forwards to [FlightRecorder.createChannel].
40+
*
41+
* @param T The type of data that will be logged to this channel
42+
* @param name The name of the channel
43+
* @param schema The schema defining how to serialize/deserialize the data
44+
* @return A new [FlightLogChannel] for logging data
45+
*/
46+
@JvmStatic
47+
fun <T> createChannel(name: String, schema: FateSchema<T>) =
48+
FlightRecorder.createChannel(name, schema)
49+
50+
/**
51+
* Creates a new log channel for a specific class type.
52+
*
53+
* Forwards to [FlightRecorder.createChannel].
54+
*
55+
* @param T The type of data that will be logged to this channel
56+
* @param name The name of the channel
57+
* @param cls The Java class representing the data type
58+
* @return A new [FlightLogChannel] for logging data
59+
*/
60+
@JvmStatic
61+
fun <T: Any> createChannel(name: String, cls: Class<T>) =
62+
FlightRecorder.createChannel(name, cls)
63+
64+
/**
65+
* Creates a new log channel for a specific class type.
66+
*
67+
* Forwards to [FlightRecorder.createChannel].
68+
*
69+
* @param T The type of data that will be logged to this channel
70+
* @param name The name of the channel
71+
* @param cls The Kotlin class representing the data type
72+
* @return A new [FlightLogChannel] for logging data
73+
*/
74+
@JvmStatic
75+
fun <T: Any> createChannel(name: String, cls: KClass<T>) =
76+
FlightRecorder.createChannel(name, cls.java)
77+
78+
/**
79+
* Writes data to a specific log channel.
80+
*
81+
* Forwards to [FlightRecorder.write].
82+
*
83+
* @param T The type of data being logged
84+
* @param channel The channel to write to
85+
* @param obj The data object to log
86+
*/
87+
@JvmStatic
88+
fun <T> write(channel: LogChannel<T>, obj: T) =
89+
FlightRecorder.write(channel, obj)
90+
91+
/**
92+
* Writes data to a channel by name.
93+
*
94+
* Forwards to [FlightRecorder.write].
95+
*
96+
* @param name The name of the channel to write to
97+
* @param obj The data object to log
98+
*/
99+
@JvmStatic
100+
fun write(name: String, obj: Any) =
101+
FlightRecorder.write(name, obj)
102+
103+
/**
104+
* Registers a publisher that will automatically supply data to a channel during periodic updates.
105+
*
106+
* The supplier will be invoked during [postWaitForStart] and [postUpdate] to retrieve
107+
* the latest data and write it to the channel.
108+
*
109+
* @param T The type of data being published
110+
* @param channel The channel to publish to
111+
* @param supplier A supplier that provides the data to log
112+
*/
113+
@JvmStatic
114+
@Suppress("UNCHECKED_CAST")
115+
fun <T> registerPublisher(channel: LogChannel<T>, supplier: Supplier<T>) {
116+
registeredPublishers[channel as LogChannel<Any>] = supplier as Supplier<Any>
117+
}
118+
119+
/**
120+
* Registers a publisher for a new channel with a custom schema.
121+
*
122+
* This convenience method creates a channel and registers a publisher in one call.
123+
*
124+
* @param T The type of data being published
125+
* @param name The name of the channel to create
126+
* @param schema The schema defining how to serialize/deserialize the data
127+
* @param supplier A supplier that provides the data to log
128+
*/
129+
@JvmStatic
130+
fun <T> registerPublisher(name: String, schema: FateSchema<T>, supplier: Supplier<T>) {
131+
registerPublisher(createChannel(name, schema), supplier)
132+
}
133+
134+
/**
135+
* Registers a publisher for a new channel with a Java class type.
136+
*
137+
* This convenience method creates a channel and registers a publisher in one call.
138+
*
139+
* @param T The type of data being published
140+
* @param name The name of the channel to create
141+
* @param cls The Java class representing the data type
142+
* @param supplier A supplier that provides the data to log
143+
*/
144+
@JvmStatic
145+
fun <T: Any> registerPublisher(name: String, cls: Class<T>, supplier: Supplier<T>) {
146+
registerPublisher(createChannel(name, cls), supplier)
147+
}
148+
149+
/**
150+
* Registers a publisher for a new channel with a Kotlin class type.
151+
*
152+
* This convenience method creates a channel and registers a publisher in one call.
153+
*
154+
* @param T The type of data being published
155+
* @param name The name of the channel to create
156+
* @param cls The Kotlin class representing the data type
157+
* @param supplier A supplier that provides the data to log
158+
*/
159+
@JvmStatic
160+
fun <T: Any> registerPublisher(name: String, cls: KClass<T>, supplier: Supplier<T>) {
161+
registerPublisher(createChannel(name, cls), supplier)
162+
}
163+
164+
override fun preInit() {
165+
snapshotChannel = createChannel("CommandSnapshot", Array<String>::class)
166+
}
167+
168+
override fun postWaitForStart() {
169+
snapshotChannel.put(CommandManager.snapshot.toTypedArray())
170+
registeredPublishers.forEach { (channel, supplier) ->
171+
write(channel, supplier.get())
172+
}
173+
FlightRecorder.timestamp()
174+
}
175+
176+
override fun postUpdate() {
177+
snapshotChannel.put(CommandManager.snapshot.toTypedArray())
178+
registeredPublishers.forEach { (channel, supplier) ->
179+
write(channel, supplier.get())
180+
}
181+
FlightRecorder.timestamp()
182+
}
183+
184+
override fun postStop() {
185+
registeredPublishers.clear()
186+
}
187+
}

gradle.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ dev.nextftc.publishing.automaticMavenCentralSync=true
77
android.useAndroidX=true
88

99
versions.roadrunner=1.0.1
10-
versions.pedro=1.0.0
10+
versions.pedro=1.0.0
11+
versions.fateweaver=1.0.0

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ ftc = "10.3.0"
77
pedro = "2.0.0"
88
rr-core = "1.0.1"
99
rr-ftc = "0.1.25"
10+
fateweaver = "0.3.3"
1011

1112
[libraries]
1213
kotest-runner = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
1314
kotest-assertations = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
1415
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" }
1516
mockk = { module = "io.mockk:mockk", version = "1.14.2" } # if needed
17+
fateweaver = { module = "gay.zharel.fateweaver:ftc", version.ref = "fateweaver" }
1618
functional-interfaces = { module = "dev.nextftc:functional-interfaces", version = "1.0.1" } # if needed
1719
ftc-robot-core = { group = "org.firstinspires.ftc", name = "RobotCore", version.ref = "ftc" }
1820
ftc-hardware = { group = "org.firstinspires.ftc", name = "Hardware", version.ref = "ftc" }

settings.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ dependencyResolutionManagement {
2020
}
2121

2222
rootProject.name = "Extensions"
23-
include(":pedro", ":roadrunner")
23+
include(":pedro", ":roadrunner", ":fateweaver")

0 commit comments

Comments
 (0)