diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml new file mode 100644 index 0000000..f432cf1 --- /dev/null +++ b/.idea/caches/deviceStreaming.xml @@ -0,0 +1,1809 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..9c3d95a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/markdown.xml b/.idea/markdown.xml new file mode 100644 index 0000000..c61ea33 --- /dev/null +++ b/.idea/markdown.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt index d60f1ff..0e60a92 100644 --- a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt +++ b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt @@ -71,7 +71,13 @@ class NextFeedbackCRServo( feedbackName: String, cacheTolerance: Double = 0.01, ) : this( - { CRServoImplEx(LynxServoController(RobotController.appContext, module), port, ServoConfigurationType.getStandardServoType()) }, + { + CRServoImplEx( + LynxServoController(RobotController.appContext, module), + port, + ServoConfigurationType.getStandardServoType(), + ) + }, feedbackName, cacheTolerance, ) diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDigitalSensor.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDigitalSensor.kt new file mode 100644 index 0000000..cc54591 --- /dev/null +++ b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDigitalSensor.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2026 NextFTC Team + * + * Use of this source code is governed by an BSD-3-clause + * license that can be found in the LICENSE.md file at the root of this repository or at + * https://opensource.org/license/bsd-3-clause. + */ + +package dev.nextftc.hardware.sensors + +import com.qualcomm.robotcore.hardware.DigitalChannel +import dev.nextftc.hardware.LazyHardware +import dev.nextftc.hardware.RobotController + +/** + * Lightweight wrapper around a [DigitalChannel] for reading digital sensors + * like limit switches, magnetic switches, and beam breaks. + * + * Most digital sensors are "active low" — they read `false` when triggered + * (switch pressed, magnet present, beam broken) and `true` when idle. This + * wrapper handles that inversion via [inverted] so [isTriggered] always + * means what you'd expect. + * + * Example: + * ``` + * val beamBreak = NextDigitalSensor("beamBreak") + * if (beamBreak.isTriggered) { stopMotor() } + * ``` + * + * @param initializer Lazily resolves the backing [DigitalChannel]. + * @param inverted If true, [isTriggered] returns the opposite of the raw + * sensor state — i.e. triggered when the channel reads low. For example, a + * touch sensor reads `false` while it's being pressed, so inverting makes + * [isTriggered] read `true` when pressed, which is what you'd expect. + * Defaults to true, matching most FTC digital sensors, which are active-low. + * + * @author 28shettr + */ + +class NextDigitalSensor(initializer: () -> DigitalChannel, private val inverted: Boolean = true) { + /** + * @param name Hardware map name to resolve the [DigitalChannel] from. + * @param inverted If true, [isTriggered] is the opposite of the raw state. Defaults to true. + */ + @JvmOverloads + constructor(name: String, inverted: Boolean = true) : this( + { + RobotController.hardwareMap[name] as DigitalChannel + }, + inverted, + ) + + private val sensor by LazyHardware(initializer).also { + it.applyAfterInit { channel -> channel.mode = DigitalChannel.Mode.INPUT } + } + + /** Raw state of the digital channel */ + val rawState: Boolean + get() = sensor.state + + /** True if the sensor is currently triggered (accounting for [inverted]). */ + val isTriggered: Boolean + get() = if (inverted) { + !sensor.state + } else { + sensor.state + } + + /** Returns a string of the sensor's current state for telemetry or logging. */ + fun debug(): String = "Sensor State: $isTriggered, Raw State: $rawState, Inverted: $inverted" +}