Fix motors debug server
This commit is contained in:
parent
dbf0466c64
commit
64043cf2c0
@ -11,7 +11,7 @@ import kotlinx.serialization.encoding.Encoder
|
|||||||
|
|
||||||
public class DeviceMessage : Scheme() {
|
public class DeviceMessage : Scheme() {
|
||||||
public var action: String by string { error("Action not defined") }
|
public var action: String by string { error("Action not defined") }
|
||||||
public var status: String by string(default = RESPONSE_OK_STATUS)
|
public var status: String by string(default = OK_STATUS)
|
||||||
public var sourceName: String? by string()
|
public var sourceName: String? by string()
|
||||||
public var targetName: String? by string()
|
public var targetName: String? by string()
|
||||||
public var comment: String? by string()
|
public var comment: String? by string()
|
||||||
@ -25,9 +25,9 @@ public class DeviceMessage : Scheme() {
|
|||||||
public val MESSAGE_KEY_KEY: Name = DeviceMessage::key.name.asName()
|
public val MESSAGE_KEY_KEY: Name = DeviceMessage::key.name.asName()
|
||||||
public val MESSAGE_VALUE_KEY: Name = DeviceMessage::value.name.asName()
|
public val MESSAGE_VALUE_KEY: Name = DeviceMessage::value.name.asName()
|
||||||
|
|
||||||
public const val RESPONSE_OK_STATUS: String = "response.OK"
|
public const val OK_STATUS: String = "OK"
|
||||||
public const val RESPONSE_FAIL_STATUS: String = "response.FAIL"
|
public const val FAIL_STATUS: String = "FAIL"
|
||||||
public const val PROPERTY_CHANGED_ACTION: String = "event.propertyChange"
|
public const val PROPERTY_CHANGED_ACTION: String = "event.propertyChanged"
|
||||||
|
|
||||||
public inline fun ok(
|
public inline fun ok(
|
||||||
request: DeviceMessage? = null,
|
request: DeviceMessage? = null,
|
||||||
@ -42,7 +42,7 @@ public class DeviceMessage : Scheme() {
|
|||||||
block: DeviceMessage.() -> Unit = {},
|
block: DeviceMessage.() -> Unit = {},
|
||||||
): DeviceMessage = DeviceMessage {
|
): DeviceMessage = DeviceMessage {
|
||||||
targetName = request?.sourceName
|
targetName = request?.sourceName
|
||||||
status = RESPONSE_FAIL_STATUS
|
status = FAIL_STATUS
|
||||||
if (cause != null) {
|
if (cause != null) {
|
||||||
configure {
|
configure {
|
||||||
set("error.type", cause::class.simpleName)
|
set("error.type", cause::class.simpleName)
|
||||||
|
@ -9,6 +9,8 @@ kotlin{
|
|||||||
explicitApi = null
|
explicitApi = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ktorVersion: String by rootProject.extra
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":dataforge-device-core"))
|
implementation(project(":dataforge-device-core"))
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ abstract class VirtualDevice(val scope: CoroutineScope) : Socket<ByteArray> {
|
|||||||
private val toReceive = Channel<ByteArray>(100)
|
private val toReceive = Channel<ByteArray>(100)
|
||||||
private val toRespond = Channel<ByteArray>(100)
|
private val toRespond = Channel<ByteArray>(100)
|
||||||
|
|
||||||
private val receiveJob: Job = toReceive.consumeAsFlow().onEach {
|
private val receiveJob: Job = toReceive.consumeAsFlow().transformRequests().onEach {
|
||||||
evaluateRequest(it)
|
evaluateRequest(it)
|
||||||
}.catch {
|
}.catch {
|
||||||
it.printStackTrace()
|
it.printStackTrace()
|
||||||
@ -48,7 +48,9 @@ abstract class VirtualDevice(val scope: CoroutineScope) : Socket<ByteArray> {
|
|||||||
|
|
||||||
class VirtualPort(private val device: VirtualDevice, context: Context) : AbstractPort(context) {
|
class VirtualPort(private val device: VirtualDevice, context: Context) : AbstractPort(context) {
|
||||||
|
|
||||||
private val respondJob = device.receiving().onEach(::receive).catch {
|
private val respondJob = device.receiving().onEach {
|
||||||
|
receive(it)
|
||||||
|
}.catch {
|
||||||
it.printStackTrace()
|
it.printStackTrace()
|
||||||
}.launchIn(scope)
|
}.launchIn(scope)
|
||||||
|
|
||||||
@ -129,7 +131,7 @@ class PiMotionMasterVirtualDevice(scope: CoroutineScope, axisIds: List<String>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun respondForAllAxis(axisIds: List<String>, extract: VirtualAxisState.(index: String) -> Any) {
|
private fun respondForAllAxis(axisIds: List<String>, extract: VirtualAxisState.(index: String) -> Any) {
|
||||||
val selectedAxis = if (axisIds.isEmpty()) {
|
val selectedAxis = if (axisIds.isEmpty()|| axisIds[0] == "ALL") {
|
||||||
axisState.keys
|
axisState.keys
|
||||||
} else {
|
} else {
|
||||||
axisIds
|
axisIds
|
||||||
@ -149,9 +151,23 @@ class PiMotionMasterVirtualDevice(scope: CoroutineScope, axisIds: List<String>)
|
|||||||
val axisIds: List<String> = parts.drop(1)
|
val axisIds: List<String> = parts.drop(1)
|
||||||
|
|
||||||
when (command) {
|
when (command) {
|
||||||
"XXX" -> respond("")
|
"XXX" -> {}//respond("WAT?")
|
||||||
"IDN?" -> respond("DataForge-device demo")
|
"IDN?","*IDN?" -> respond("(c)2015 Physik Instrumente(PI) Karlsruhe, C-885.M1 TCP-IP Master,0,1.0.0.1")
|
||||||
"VER?" -> respond("test")
|
"VER?" -> respond("""
|
||||||
|
2: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550039, 00.039
|
||||||
|
3: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550040, 00.039
|
||||||
|
4: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550041, 00.039
|
||||||
|
5: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550042, 00.039
|
||||||
|
6: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550043, 00.039
|
||||||
|
7: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550044, 00.039
|
||||||
|
8: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550046, 00.039
|
||||||
|
9: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550045, 00.039
|
||||||
|
10: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550047, 00.039
|
||||||
|
11: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550048, 00.039
|
||||||
|
12: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550049, 00.039
|
||||||
|
13: (c)2017 Physik Instrumente (PI) GmbH & Co. KG, C-663.12C885, 018550051, 00.039
|
||||||
|
FW_ARM: V1.0.0.1
|
||||||
|
""".trimIndent())
|
||||||
"HLP?" -> respond("""
|
"HLP?" -> respond("""
|
||||||
The following commands are valid:
|
The following commands are valid:
|
||||||
#4 Request Status Register
|
#4 Request Status Register
|
||||||
@ -192,7 +208,10 @@ class PiMotionMasterVirtualDevice(scope: CoroutineScope, axisIds: List<String>)
|
|||||||
VER? Get Versions Of Firmware And Drivers
|
VER? Get Versions Of Firmware And Drivers
|
||||||
end of help
|
end of help
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
"ERR?" -> respond(errorCode.toString())
|
"ERR?" -> {
|
||||||
|
respond(errorCode.toString())
|
||||||
|
errorCode = 0
|
||||||
|
}
|
||||||
"SAI?" -> respondForAllAxis(axisIds) { it }
|
"SAI?" -> respondForAllAxis(axisIds) { it }
|
||||||
"CST?" -> respond(WAT)
|
"CST?" -> respond(WAT)
|
||||||
"RON?" -> respondForAllAxis(axisIds) { referenceMode }
|
"RON?" -> respondForAllAxis(axisIds) { referenceMode }
|
||||||
|
@ -9,55 +9,52 @@ import io.ktor.network.sockets.openWriteChannel
|
|||||||
import io.ktor.util.InternalAPI
|
import io.ktor.util.InternalAPI
|
||||||
import io.ktor.util.KtorExperimentalAPI
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
import io.ktor.util.moveToByteArray
|
import io.ktor.util.moveToByteArray
|
||||||
import io.ktor.utils.io.readUntilDelimiter
|
|
||||||
import io.ktor.utils.io.writeAvailable
|
import io.ktor.utils.io.writeAvailable
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
private val delimeter = ByteBuffer.wrap("\n".encodeToByteArray())
|
val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
|
||||||
|
throwable.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(KtorExperimentalAPI::class, InternalAPI::class)
|
@OptIn(KtorExperimentalAPI::class, InternalAPI::class)
|
||||||
fun CoroutineScope.launchPiDebugServer(port: Int, virtualPort: Port): Job = launch {
|
fun CoroutineScope.launchPiDebugServer(port: Int, virtualPort: Port): Job = launch(exceptionHandler) {
|
||||||
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}")
|
||||||
|
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val socket = try {
|
val socket = server.accept()
|
||||||
server.accept()
|
launch(SupervisorJob(coroutineContext[Job])) {
|
||||||
} catch (ex: Exception) {
|
|
||||||
server.close()
|
|
||||||
ex.printStackTrace()
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
println("Socket accepted: ${socket.remoteAddress}")
|
println("Socket accepted: ${socket.remoteAddress}")
|
||||||
supervisorScope {
|
|
||||||
socket.use { socket ->
|
|
||||||
val input = socket.openReadChannel()
|
val input = socket.openReadChannel()
|
||||||
val output = socket.openWriteChannel(autoFlush = true)
|
val output = socket.openWriteChannel()
|
||||||
|
|
||||||
val buffer = ByteBuffer.allocate(1024)
|
val sendJob = launch {
|
||||||
launch {
|
|
||||||
virtualPort.receiving().collect {
|
virtualPort.receiving().collect {
|
||||||
//println("Sending: ${it.decodeToString()}")
|
//println("Sending: ${it.decodeToString()}")
|
||||||
output.writeAvailable(it)
|
output.writeAvailable(it)
|
||||||
output.flush()
|
output.flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
buffer.rewind()
|
input.read { buffer ->
|
||||||
val read = input.readUntilDelimiter(delimeter, buffer)
|
|
||||||
if (read > 0) {
|
|
||||||
buffer.flip()
|
|
||||||
val array = buffer.moveToByteArray()
|
val array = buffer.moveToByteArray()
|
||||||
//println("Received: ${array.decodeToString()}")
|
launch {
|
||||||
virtualPort.send(array)
|
virtualPort.send(array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
e.printStackTrace()
|
||||||
|
sendJob.cancel()
|
||||||
|
socket.close()
|
||||||
|
} finally {
|
||||||
|
println("Socket closed")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user