initial
This commit is contained in:
commit
b24ebba1f6
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
### IntelliJ IDEA ###
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Kotlin ###
|
||||
.kotlin
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
/.idea/misc.xml
|
||||
3
.idea/.gitignore
vendored
Normal file
3
.idea/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
7
.idea/codeStyles/Project.xml
Normal file
7
.idea/codeStyles/Project.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<ScalaCodeStyleSettings>
|
||||
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
|
||||
</ScalaCodeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="ReplaceUntilWithRangeUntil" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
10
.idea/kotlinc.xml
Normal file
10
.idea/kotlinc.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Kotlin2JvmCompilerArguments">
|
||||
<option name="jvmTarget" value="1.8" />
|
||||
</component>
|
||||
<component name="KotlinCommonCompilerArguments">
|
||||
<option name="apiVersion" value="2.1" />
|
||||
<option name="languageVersion" value="2.1" />
|
||||
</component>
|
||||
</project>
|
||||
17
.idea/libraries/KotlinJavaRuntime.xml
Normal file
17
.idea/libraries/KotlinJavaRuntime.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<component name="libraryTable">
|
||||
<library name="KotlinJavaRuntime" type="repository">
|
||||
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib:2.1.0" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0-javadoc.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/VFHeatControl.iml" filepath="$PROJECT_DIR$/VFHeatControl.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
15
VFHeatControl.iml
Normal file
15
VFHeatControl.iml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
90
src/main/kotlin/dev/asdf00/visionfive/hc/Gpio.kt
Normal file
90
src/main/kotlin/dev/asdf00/visionfive/hc/Gpio.kt
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package dev.asdf00.visionfive.hc
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
class GpioPin(val num: Int, val isInput: Boolean) : AutoCloseable {
|
||||
var state: Boolean = false
|
||||
get() {
|
||||
if (isInput)
|
||||
field = Files.readString(valuePath) == "1\n"
|
||||
return field
|
||||
}
|
||||
set(newVal) {
|
||||
if (isInput)
|
||||
throw IllegalStateException("can not write state of input")
|
||||
if (field == newVal)
|
||||
return
|
||||
if (!isInput)
|
||||
Files.writeString(valuePath, if (newVal) "1" else "0")
|
||||
field = newVal
|
||||
}
|
||||
|
||||
private val basePath get() = Path.of("/sys/class/gpio")
|
||||
private val pinPath get() = basePath.resolve("gpio$num")
|
||||
private val valuePath get() = pinPath.resolve("value")
|
||||
|
||||
init {
|
||||
if (num !in ALLOWED_PINS)
|
||||
throw IllegalArgumentException("GPIO$num does not exist!")
|
||||
println("initializing with 'echo $num > ${basePath.resolve("export")}'")
|
||||
Files.writeString(basePath.resolve("export"), "$num")
|
||||
Files.writeString(basePath.resolve("gpio$num").resolve("direction"), if (isInput) "in" else "out")
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
if (!isInput)
|
||||
state = false
|
||||
Files.writeString(basePath.resolve("unexport"), "$num")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val ALLOWED_PINS = setOf(58, 57, 55, 5, 6, 42, 38, 43, 47, 54, 51, 52, 53, 50, 48, 49, 56, 45, 40, 37, 39, 46, 59, 63, 36, 60, 61, 44)
|
||||
}
|
||||
}
|
||||
|
||||
class PinGroup(vararg val pins: GpioPin) {
|
||||
var state: BooleanArray
|
||||
get() = BooleanArray(pins.size) { pins[it].state }
|
||||
set(nuStates) {
|
||||
if (nuStates.size != pins.size)
|
||||
throw IllegalArgumentException("state count mismatch, expected ${pins.size}, got ${nuStates.size}")
|
||||
for (i in nuStates.indices)
|
||||
pins[i].state = nuStates[i]
|
||||
}
|
||||
|
||||
var intState: Long
|
||||
get() {
|
||||
if (pins.size > 64)
|
||||
throw UnsupportedOperationException("can not use intState for PinGroup with more than 64 pins")
|
||||
var l = 0L
|
||||
for (i in pins.indices.reversed()) {
|
||||
l = l shl 1
|
||||
l = l or if (pins[i].state) 1 else 0
|
||||
}
|
||||
return l
|
||||
}
|
||||
set(value) {
|
||||
var l = value
|
||||
if (pins.size > 64)
|
||||
throw UnsupportedOperationException("can not use intState for PinGroup with more than 64 pins")
|
||||
for (i in pins.indices) {
|
||||
pins[i].state = l and 1 == 1L
|
||||
l = l ushr 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun usingPins(vararg pins: Pair<Int, Boolean>, body: (Array<GpioPin>) -> Unit) {
|
||||
fun recUsingPins(i: Int, pins: Array<GpioPin?>, pinIds: Array<out Pair<Int, Boolean>>, body: (Array<GpioPin>) -> Unit) {
|
||||
if (i < pins.size) {
|
||||
GpioPin(pinIds[i].first, pinIds[i].second).use {
|
||||
pins[i] = it
|
||||
recUsingPins(i + 1, pins, pinIds, body)
|
||||
}
|
||||
} else {
|
||||
body(Array(pins.size) { pins[it]!! })
|
||||
}
|
||||
}
|
||||
recUsingPins(0, arrayOfNulls(pins.size), pins, body)
|
||||
}
|
||||
115
src/main/kotlin/dev/asdf00/visionfive/hc/MotorControl.kt
Normal file
115
src/main/kotlin/dev/asdf00/visionfive/hc/MotorControl.kt
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package dev.asdf00.visionfive.hc
|
||||
|
||||
class Controller(private val senseBot: GpioPin, private val senseTop: GpioPin, private val motor: PinGroup) {
|
||||
constructor(senseBot: GpioPin, senseTop: GpioPin, m0: GpioPin, m1: GpioPin, m2: GpioPin, m3: GpioPin) : this(
|
||||
senseBot,
|
||||
senseTop,
|
||||
PinGroup(m0, m1, m2, m3)
|
||||
)
|
||||
|
||||
init {
|
||||
motor.intState = initialStep
|
||||
}
|
||||
|
||||
private var internalState = -1
|
||||
private var maxStep = -1
|
||||
|
||||
var state: Double
|
||||
get() = if (internalState < 0) Double.NaN else internalState.toDouble() / maxStep.toDouble()
|
||||
set(target) {
|
||||
if (internalState < 0)
|
||||
throw IllegalStateException("call Controller#runInitSequence before using it")
|
||||
TODO()
|
||||
}
|
||||
|
||||
fun runInitSequence() {
|
||||
val prevState = runToBot()
|
||||
val range = runToTop()
|
||||
stepClock(range - prevState)
|
||||
internalState = prevState
|
||||
maxStep = range
|
||||
}
|
||||
|
||||
private fun stepClock(cnt: Int = 1): Int {
|
||||
var actual = cnt
|
||||
for (i in 0..<cnt) {
|
||||
if (!senseBot.state) {
|
||||
doStep(clockStep)
|
||||
} else {
|
||||
actual = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return actual
|
||||
}
|
||||
|
||||
private fun stepAnti(cnt: Int = 1): Int {
|
||||
var actual = cnt
|
||||
for (i in 0..<cnt) {
|
||||
if (!senseTop.state) {
|
||||
doStep(antiStep)
|
||||
} else {
|
||||
actual = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return actual
|
||||
}
|
||||
|
||||
private fun runToBot(): Int {
|
||||
var i = 0
|
||||
while (true) {
|
||||
if (senseBot.state)
|
||||
return i
|
||||
doStep(clockStep)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
private fun runToTop(): Int {
|
||||
var i = 0
|
||||
while (true) {
|
||||
if (senseTop.state)
|
||||
return i
|
||||
doStep(antiStep)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
private fun doStep(step: LongArray) {
|
||||
assert(motor.intState == initialStep, { "step must ALWAYS start on initial step state" })
|
||||
for (l in step) {
|
||||
motor.intState = l
|
||||
Thread.sleep(stepDelay)
|
||||
}
|
||||
assert(motor.intState == initialStep, { "step must ALWAYS end on initial step state" })
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val stepDelay = 10L
|
||||
|
||||
private val initialStep = 0b1001L
|
||||
|
||||
private val clockStep = longArrayOf(
|
||||
0b0001,
|
||||
0b0011,
|
||||
0b0010,
|
||||
0b0110,
|
||||
0b0100,
|
||||
0b1100,
|
||||
0b1000,
|
||||
0b1001,
|
||||
)
|
||||
|
||||
private val antiStep = longArrayOf(
|
||||
0b1000,
|
||||
0b1100,
|
||||
0b0100,
|
||||
0b0110,
|
||||
0b0010,
|
||||
0b0011,
|
||||
0b0001,
|
||||
0b1001,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user