Fix motors parser
This commit is contained in:
parent
eb3121aed4
commit
23c66d9703
@ -32,11 +32,11 @@ public class TypedDeviceProperty<T : Any>(
|
|||||||
converter: MetaConverter<T>,
|
converter: MetaConverter<T>,
|
||||||
) : TypedReadOnlyDeviceProperty<T>(property, converter), DeviceProperty {
|
) : TypedReadOnlyDeviceProperty<T>(property, converter), DeviceProperty {
|
||||||
|
|
||||||
// override var value: MetaItem<*>?
|
override var value: MetaItem<*>?
|
||||||
// get() = property.value
|
get() = property.value
|
||||||
// set(arg) {
|
set(arg) {
|
||||||
// property.value = arg
|
property.value = arg
|
||||||
// }
|
}
|
||||||
|
|
||||||
public override var typedValue: T?
|
public override var typedValue: T?
|
||||||
get() = value?.let { converter.itemToObject(it) }
|
get() = value?.let { converter.itemToObject(it) }
|
||||||
|
@ -40,7 +40,7 @@ public abstract class AbstractPort(
|
|||||||
*/
|
*/
|
||||||
protected fun receive(data: ByteArray) {
|
protected fun receive(data: ByteArray) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
logger.debug { "[${this@AbstractPort}] RECEIVED: ${data.decodeToString()}" }
|
logger.debug { "${this@AbstractPort} RECEIVED: ${data.decodeToString()}" }
|
||||||
incoming.send(data)
|
incoming.send(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ public abstract class AbstractPort(
|
|||||||
for (data in outgoing) {
|
for (data in outgoing) {
|
||||||
try {
|
try {
|
||||||
write(data)
|
write(data)
|
||||||
logger.debug { "[${this@AbstractPort}] SENT: ${data.decodeToString()}" }
|
logger.debug { "${this@AbstractPort} SENT: ${data.decodeToString()}" }
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
if (ex is CancellationException) throw ex
|
if (ex is CancellationException) throw ex
|
||||||
logger.error(ex) { "Error while writing data to the port" }
|
logger.error(ex) { "Error while writing data to the port" }
|
||||||
|
@ -9,7 +9,7 @@ plugins {
|
|||||||
|
|
||||||
kotlin{
|
kotlin{
|
||||||
explicitApi = null
|
explicitApi = null
|
||||||
useFx(ru.mipt.npm.gradle.FXModule.CONTROLS)
|
useFx(ru.mipt.npm.gradle.FXModule.CONTROLS, configuration = ru.mipt.npm.gradle.DependencyConfiguration.IMPLEMENTATION)
|
||||||
}
|
}
|
||||||
|
|
||||||
val ktorVersion: String by rootProject.extra
|
val ktorVersion: String by rootProject.extra
|
||||||
|
@ -3,6 +3,7 @@ package ru.mipt.npm.devices.pimotionmaster
|
|||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.control.controllers.DeviceManager
|
import hep.dataforge.control.controllers.DeviceManager
|
||||||
import hep.dataforge.control.controllers.installing
|
import hep.dataforge.control.controllers.installing
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
@ -27,20 +28,29 @@ class PiMotionMasterView : View() {
|
|||||||
|
|
||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
top {
|
top {
|
||||||
hbox {
|
form {
|
||||||
val host = SimpleStringProperty("127.0.0.1")
|
val host = SimpleStringProperty("127.0.0.1")
|
||||||
val port = SimpleIntegerProperty(10024)
|
val port = SimpleIntegerProperty(10024)
|
||||||
|
val virtual = SimpleBooleanProperty(false)
|
||||||
fieldset("Address:") {
|
fieldset("Address:") {
|
||||||
field("Host:") {
|
field("Host:") {
|
||||||
textfield(host)
|
textfield(host){
|
||||||
|
enableWhen(virtual.not())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
field("Port:") {
|
field("Port:") {
|
||||||
textfield(port)
|
textfield(port)
|
||||||
}
|
}
|
||||||
|
field("Virtual device:") {
|
||||||
|
checkbox(property = virtual)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button("Connect") {
|
button("Connect") {
|
||||||
action {
|
action {
|
||||||
|
if(virtual.get()){
|
||||||
|
controller.context.launchPiDebugServer(port.get(), listOf("1", "2"))
|
||||||
|
}
|
||||||
controller.motionMaster.connect(host.get(), port.get())
|
controller.motionMaster.connect(host.get(), port.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,9 @@ import hep.dataforge.control.controllers.*
|
|||||||
import hep.dataforge.control.ports.*
|
import hep.dataforge.control.ports.*
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.values.Null
|
|
||||||
import hep.dataforge.values.asValue
|
import hep.dataforge.values.asValue
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.takeWhile
|
|
||||||
import kotlinx.coroutines.flow.toList
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
@ -32,10 +29,13 @@ class PiMotionMasterDevice(
|
|||||||
context.coroutineContext + SupervisorJob(context.coroutineContext[Job])
|
context.coroutineContext + SupervisorJob(context.coroutineContext[Job])
|
||||||
)
|
)
|
||||||
|
|
||||||
val address: DeviceProperty by writingVirtual(Null) {
|
private var address: Meta? = null
|
||||||
info = "The port for TCP connector"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
val connected by readingBoolean(false, descriptorBuilder = {
|
||||||
|
info = "True if the connection address is defined and the device is initialized"
|
||||||
|
}) {
|
||||||
|
address != null
|
||||||
|
}
|
||||||
|
|
||||||
val timeout: DeviceProperty by writingVirtual(200.asValue()) {
|
val timeout: DeviceProperty by writingVirtual(200.asValue()) {
|
||||||
info = "Timeout"
|
info = "Timeout"
|
||||||
@ -43,8 +43,7 @@ class PiMotionMasterDevice(
|
|||||||
|
|
||||||
var timeoutValue: Duration by timeout.duration()
|
var timeoutValue: Duration by timeout.duration()
|
||||||
|
|
||||||
private val connector = PortProxy { portFactory(address.value.node ?: Meta.EMPTY, context) }
|
private val connector = PortProxy { portFactory(address ?: error("The device is not connected"), context) }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name-friendly accessor for axis
|
* Name-friendly accessor for axis
|
||||||
@ -63,11 +62,13 @@ class PiMotionMasterDevice(
|
|||||||
info = "Connect to specific port and initialize axis"
|
info = "Connect to specific port and initialize axis"
|
||||||
}) { portSpec ->
|
}) { portSpec ->
|
||||||
//Clear current actions if present
|
//Clear current actions if present
|
||||||
if (address.value != null) {
|
if (address != null) {
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
//Update port
|
//Update port
|
||||||
address.value = portSpec
|
address = portSpec.node
|
||||||
|
connected.invalidate()
|
||||||
|
connector.open()
|
||||||
//Initialize axes
|
//Initialize axes
|
||||||
if (portSpec != null) {
|
if (portSpec != null) {
|
||||||
val idn = identity.read()
|
val idn = identity.read()
|
||||||
@ -84,6 +85,17 @@ class PiMotionMasterDevice(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val disconnect: DeviceAction by acting({
|
||||||
|
info = "Disconnect the program from the device if it is connected"
|
||||||
|
}) {
|
||||||
|
connector.close()
|
||||||
|
if (address != null) {
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
address = null
|
||||||
|
connected.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
fun connect(host: String, port: Int) {
|
fun connect(host: String, port: Int) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
connect(Meta {
|
connect(Meta {
|
||||||
@ -126,7 +138,16 @@ class PiMotionMasterDevice(
|
|||||||
withTimeout(timeoutValue) {
|
withTimeout(timeoutValue) {
|
||||||
sendCommandInternal(command, *arguments)
|
sendCommandInternal(command, *arguments)
|
||||||
val phrases = connector.receiving().withDelimiter("\n")
|
val phrases = connector.receiving().withDelimiter("\n")
|
||||||
phrases.takeWhile { it.endsWith(" \n") }.toList() + phrases.first()
|
var lastLineFlag = false
|
||||||
|
phrases.transformWhile { line ->
|
||||||
|
if (lastLineFlag) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
emit(line)
|
||||||
|
lastLineFlag = !line.endsWith(" \n")
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}.toList()
|
||||||
}
|
}
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
logger.warn { "Error during PIMotionMaster request. Requesting error code." }
|
logger.warn { "Error during PIMotionMaster request. Requesting error code." }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package ru.mipt.npm.devices.pimotionmaster
|
package ru.mipt.npm.devices.pimotionmaster
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.control.ports.Port
|
|
||||||
import io.ktor.network.selector.ActorSelectorManager
|
import io.ktor.network.selector.ActorSelectorManager
|
||||||
import io.ktor.network.sockets.aSocket
|
import io.ktor.network.sockets.aSocket
|
||||||
import io.ktor.network.sockets.openReadChannel
|
import io.ktor.network.sockets.openReadChannel
|
||||||
@ -19,7 +19,8 @@ val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(KtorExperimentalAPI::class, InternalAPI::class)
|
@OptIn(KtorExperimentalAPI::class, InternalAPI::class)
|
||||||
fun CoroutineScope.launchPiDebugServer(port: Int, virtualPort: Port): Job = launch(exceptionHandler) {
|
fun Context.launchPiDebugServer(port: Int, axes: List<String>): Job = launch(exceptionHandler) {
|
||||||
|
val virtualDevice = PiMotionMasterVirtualDevice(this@launchPiDebugServer, axes)
|
||||||
val server = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().bind(InetSocketAddress("localhost", port))
|
val server = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().bind(InetSocketAddress("localhost", port))
|
||||||
println("Started virtual port server at ${server.localAddress}")
|
println("Started virtual port server at ${server.localAddress}")
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ fun CoroutineScope.launchPiDebugServer(port: Int, virtualPort: Port): Job = laun
|
|||||||
val output = socket.openWriteChannel()
|
val output = socket.openWriteChannel()
|
||||||
|
|
||||||
val sendJob = launch {
|
val sendJob = launch {
|
||||||
virtualPort.receiving().collect {
|
virtualDevice.receiving().collect {
|
||||||
//println("Sending: ${it.decodeToString()}")
|
//println("Sending: ${it.decodeToString()}")
|
||||||
output.writeAvailable(it)
|
output.writeAvailable(it)
|
||||||
output.flush()
|
output.flush()
|
||||||
@ -43,7 +44,7 @@ fun CoroutineScope.launchPiDebugServer(port: Int, virtualPort: Port): Job = laun
|
|||||||
input.read { buffer ->
|
input.read { buffer ->
|
||||||
val array = buffer.moveToByteArray()
|
val array = buffer.moveToByteArray()
|
||||||
launch {
|
launch {
|
||||||
virtualPort.send(array)
|
virtualDevice.send(array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,10 +62,8 @@ fun CoroutineScope.launchPiDebugServer(port: Int, virtualPort: Port): Job = laun
|
|||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val port = 10024
|
val port = 10024
|
||||||
val virtualDevice = PiMotionMasterVirtualDevice(Global, listOf("1", "2"))
|
|
||||||
val virtualPort = VirtualPort(virtualDevice, Global)
|
|
||||||
runBlocking(Dispatchers.Default) {
|
runBlocking(Dispatchers.Default) {
|
||||||
val serverJob = launchPiDebugServer(port, virtualPort)
|
val serverJob = Global.launchPiDebugServer(port, listOf("1", "2"))
|
||||||
readLine()
|
readLine()
|
||||||
serverJob.cancel()
|
serverJob.cancel()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user