Skip to content

Commit

Permalink
Merge pull request #61 from strykeforce/rewrite-measure
Browse files Browse the repository at this point in the history
Convert Measure enum to data class
  • Loading branch information
jhh authored Sep 25, 2019
2 parents ccbe7e9 + d18551a commit 0cc9143
Show file tree
Hide file tree
Showing 19 changed files with 427 additions and 493 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ buildscript {
}
dependencies {
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.+'
classpath "edu.wpi.first:GradleRIO:2019.1.1"
classpath "com.diffplug.spotless:spotless-plugin-gradle:3.15.0"
classpath "edu.wpi.first:GradleRIO:2019.4.1"
classpath "com.diffplug.spotless:spotless-plugin-gradle:3.24.2"
}
}

configure(subprojects) {
group = 'org.strykeforce.thirdcoast'
version = '19.3.0'
version = '19.4.0'

apply plugin: 'java-library'
apply plugin: 'idea'
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
githubUrl=https://github.com/strykeforce/thirdcoast
kotlin.code.style=official
10 changes: 5 additions & 5 deletions telemetry/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext {
kotlin_version = '1.3.20'
kotlin_version = '1.3.50'
junit_version = '5.2.0'
}

Expand All @@ -10,7 +10,7 @@ buildscript {
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.9.17"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:0.9.18"
}
}

Expand All @@ -29,14 +29,14 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

// telemetry
implementation "org.eclipse.jetty:jetty-server:9.4.12.v20180830"
implementation "org.eclipse.jetty:jetty-server:9.4.19.v20190610"
implementation "com.squareup.moshi:moshi:1.8.0"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.8.0"
implementation "com.squareup.okhttp3:okhttp:3.12.0"
implementation "com.squareup.okhttp3:okhttp:3.12.5"
implementation project(':swerve')

// Logging
compile 'io.github.microutils:kotlin-logging:1.6.10'
compile 'io.github.microutils:kotlin-logging:1.7.6'

// unit tests
testImplementation 'org.skyscreamer:jsonassert:1.+'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private fun JsonWriter.writeItems(items: List<Measurable>): JsonWriter {

private fun JsonWriter.writeMeasures(items: List<Measurable>): JsonWriter {
beginArray()
items.associateBy({ it.type }, { it.measures }).forEach { type, measures ->
items.associateBy({ it.type }, { it.measures }).forEach { (type, measures) ->
beginObject()
name("deviceType").value(type)
name("deviceMeasures")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,124 +11,126 @@ import java.util.function.Function
private val logger = KotlinLogging.logger {}

/**
* The Telemetry service registers [Measurable] instances for data collection and controls the
* starting and stopping of the service. When active, the services listens for incoming config
* messages via a HTTP REST service and sends data over UDP.
* The Telemetry service is the main interface for client applications that are telemetry-enabled. It registers
* [Measurable] instances for data collection and controls the starting and stopping of the service. When active,
* the services listens for incoming control messages via a HTTP REST-like service and sends data over UDP.
*
* The constructor takes a factory function to create a [TelemetryController] instance with a given [Inventory].
* The default [TelemetryController] has a constructor that serves this purpose, for example:
* ```
* TelemetryService ts = new TelemetryService(TelemetryController::new);
* ts.register(talon);
* ts.start();
* ```
*/
class TelemetryService(private val telemetryControllerFactory: Function<Inventory, TelemetryController>) {

// current implementation passes this list to the inventory as a collection via component binding
// when start is called. The inventory copies this collection into a List, using its index in
// this list as the inventory id.
// Current implementation passes the `items` list to the inventory as a collection when start is called. The inventory
// sorts and copies this collection into a List, using its index in this list as the inventory id. This should provide
// a stable order of measurable items that assists the Grapher client when saving its configuration.

private val items = LinkedHashSet<Measurable>()
private var telemetryController: TelemetryController? = null
private val items = LinkedHashSet<Measurable>()
private var telemetryController: TelemetryController? = null

/** Start the Telemetry service and listen for client connections. */
fun start() {
if (telemetryController != null) {
logger.info("already started")
return
}
telemetryController = telemetryControllerFactory.apply(RobotInventory(items)).also { it.start() }
logger.info("started telemetry controller")
/**
* Start the Telemetry service and listen for client connections. A new instance of [TelemetryController] is created
* that reflects the current list of [Measurable] items.
*/
fun start() {
if (telemetryController != null) {
logger.info("already started")
return
}
telemetryController = telemetryControllerFactory.apply(RobotInventory(items)).also { it.start() }
logger.info("started telemetry controller")
}

/** Stop the Telemetry service. */
fun stop() {
if (telemetryController == null) {
logger.info("already stopped")
return
}
telemetryController?.shutdown()
telemetryController = null
logger.info("stopped")
/** Stop the Telemetry service. */
fun stop() {
if (telemetryController == null) {
logger.info("already stopped")
return
}
telemetryController?.shutdown()
telemetryController = null
logger.info("stopped")
}

/**
* Un-register all Items.
*
* @throws IllegalStateException if TelemetryService is running.
*/
fun clear() {
checkNotStarted()
items.clear()
logger.info("item set was cleared")
}
/**
* Un-register all [Measurable] items.
*
* @throws IllegalStateException if TelemetryService is running.
*/
fun clear() {
check(telemetryController == null) { "TelemetryService must be stopped to clear registered items." }
items.clear()
logger.info("item set was cleared")
}

/**
* Registers an Item for telemetry sending.
*
* @param item the Item to register for data collection
* @throws IllegalStateException if TelemetryService is running.
*/
fun register(item: Measurable) {
checkNotStarted()
if (items.add(item)) {
logger.info { "registered item ${item.description}" }
return
}
logger.info { "item ${item.description} was already registered" }
/**
* Registers an Item for telemetry sending.
*
* @param item the [Measurable] to register for data collection
* @throws IllegalStateException if TelemetryService is running.
*/
fun register(item: Measurable) {
check(telemetryController == null) { "TelemetryService must be stopped to register an item." }
if (items.add(item)) {
logger.info { "registered item ${item.description}" }
return
}
logger.info { "item ${item.description} was already registered" }
}

/**
* Register a collection for telemetry sending.
*
* @param collection the collection of Items to register for data collection
* @throws IllegalStateException if TelemetryService is running.
*/
fun registerAll(collection: Collection<Measurable>) {
checkNotStarted()
items.addAll(collection)
logger.info { "registered all: $collection" }
}
/**
* Register a collection of [Measurable] items for telemetry sending.
*
* @param collection the collection of Items to register for data collection
* @throws IllegalStateException if TelemetryService is running.
*/
fun registerAll(collection: Collection<Measurable>) = collection.forEach(this::register)

/**
* Convenience method to register a `TalonSRX` for telemetry sending.
*
* @param talon the TalonSRX to register for data collection
* @throws IllegalStateException if TelemetryService is running.
*/
fun register(talon: TalonSRX) {
register(TalonItem(talon))
}
/**
* Convenience method to register a `TalonSRX` for telemetry sending.
*
* @param talon the TalonSRX to register for data collection
* @throws IllegalStateException if TelemetryService is running.
*/
fun register(talon: TalonSRX) {
register(TalonItem(talon))
}

/**
* Convenience method to register a [SwerveDrive] for telemetry sending.
*
* @throws IllegalStateException if TelemetryService is running.
*/
fun register(swerveDrive: SwerveDrive) = swerveDrive.wheels.forEach {
register(TalonItem(it.azimuthTalon))
register(TalonItem(it.driveTalon))
}
/**
* Convenience method to register a [SwerveDrive] for telemetry sending.
*
* @throws IllegalStateException if TelemetryService is running.
*/
fun register(swerveDrive: SwerveDrive) = swerveDrive.wheels.forEach {
register(TalonItem(it.azimuthTalon))
register(TalonItem(it.driveTalon))
}

/**
* Get an unmodifiable view of the registered items.
*
* @return an unmodifiable Set of Items.
*/
fun getItems(): Set<Measurable> {
return Collections.unmodifiableSet(items)
}
/**
* Get an unmodifiable view of the registered items.
*
* @return an unmodifiable Set of Items.
*/
fun getItems(): Set<Measurable> {
return Collections.unmodifiableSet(items)
}

/**
* Unregister [item] from a stopped `TelemetryService`.
*
* @throws AssertionError if TelemetryService is running.
*/
fun remove(item: Measurable) {
checkNotStarted()
if (items.remove(item)) {
logger.info { "removed $item" }
return
}
throw AssertionError(item.toString())
/**
* Unregister a [Measurable] item. This service must be stopped first.
*
* @throws AssertionError if TelemetryService is running.
*/
fun remove(item: Measurable) {
check(telemetryController == null) { "TelemetryService must be stopped to remove an item." }
if (items.remove(item)) {
logger.info { "removed $item" }
return
}
throw AssertionError(item.toString())
}

private fun checkNotStarted() {
if (telemetryController != null) {
throw IllegalStateException("TelemetryService must be stopped.")
}
}
}

This file was deleted.

Loading

0 comments on commit 0cc9143

Please sign in to comment.