Plc4X refactor
This commit is contained in:
parent
58675f72f5
commit
977500223d
@ -11,14 +11,14 @@ description = """
|
|||||||
A plugin for Controls-kt device server on top of plc4x library
|
A plugin for Controls-kt device server on top of plc4x library
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
kscience{
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
jvmMain{
|
jvmMain {
|
||||||
api(projects.controlsCore)
|
api(projects.controlsCore)
|
||||||
api("org.apache.plc4x:plc4j-spi:$plc4xVersion")
|
api("org.apache.plc4x:plc4j-spi:$plc4xVersion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readme{
|
readme {
|
||||||
maturity = Maturity.EXPERIMENTAL
|
maturity = Maturity.EXPERIMENTAL
|
||||||
}
|
}
|
@ -2,27 +2,75 @@ package space.kscience.controls.plc4x
|
|||||||
|
|
||||||
import kotlinx.coroutines.future.await
|
import kotlinx.coroutines.future.await
|
||||||
import org.apache.plc4x.java.api.PlcConnection
|
import org.apache.plc4x.java.api.PlcConnection
|
||||||
|
import org.apache.plc4x.java.api.messages.PlcBrowseItem
|
||||||
|
import org.apache.plc4x.java.api.messages.PlcTagResponse
|
||||||
import org.apache.plc4x.java.api.messages.PlcWriteRequest
|
import org.apache.plc4x.java.api.messages.PlcWriteRequest
|
||||||
|
import org.apache.plc4x.java.api.messages.PlcWriteResponse
|
||||||
|
import org.apache.plc4x.java.api.types.PlcResponseCode
|
||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
|
||||||
public interface Plc4XDevice: Device {
|
private val PlcTagResponse.responseCodes: Map<String, PlcResponseCode>
|
||||||
public val connection: PlcConnection
|
get() = tagNames.associateWith { getResponseCode(it) }
|
||||||
|
|
||||||
public suspend fun read(plc4xProperty: Plc4xProperty): Meta = with(plc4xProperty){
|
private val Map<String, PlcResponseCode>.isOK get() = values.all { it == PlcResponseCode.OK }
|
||||||
val request = connection.readRequestBuilder().request().build()
|
|
||||||
val response = request.execute().await()
|
|
||||||
response.readProperty()
|
|
||||||
}
|
|
||||||
|
|
||||||
public suspend fun write(plc4xProperty: Plc4xProperty, value: Meta): Unit = with(plc4xProperty){
|
|
||||||
val request: PlcWriteRequest = connection.writeRequestBuilder().writeProperty(value).build()
|
|
||||||
request.execute().await()
|
|
||||||
}
|
|
||||||
|
|
||||||
public suspend fun subscribe(propertyName: String, plc4xProperty: Plc4xProperty): Unit = with(plc4xProperty){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public class PlcException(public val codes: Map<String, PlcResponseCode>) : Exception() {
|
||||||
|
override val message: String
|
||||||
|
get() = "Plc request unsuccessful:" + codes.entries.joinToString(prefix = "\n\t", separator = "\n\t") {
|
||||||
|
"${it.key}: ${it.value.name}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PlcTagResponse.throwOnFail() {
|
||||||
|
val codes = responseCodes
|
||||||
|
if (!codes.isOK) throw PlcException(codes)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface Plc4XDevice : Device {
|
||||||
|
public val connection: PlcConnection
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send ping request and suspend until it comes back
|
||||||
|
*/
|
||||||
|
public suspend fun Plc4XDevice.ping(): PlcResponseCode = connection.ping().await().responseCode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send browse request to list available tags
|
||||||
|
*/
|
||||||
|
public suspend fun Plc4XDevice.browse(): Map<String, MutableList<PlcBrowseItem>> {
|
||||||
|
require(connection.metadata.isBrowseSupported){"Browse actions are not supported on connection"}
|
||||||
|
val request = connection.browseRequestBuilder().build()
|
||||||
|
val response = request.execute().await()
|
||||||
|
|
||||||
|
return response.queryNames.associateWith { response.getValues(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send read request and suspend until it returns. Throw a [PlcException] if at least one tag read fails.
|
||||||
|
*
|
||||||
|
* @throws PlcException
|
||||||
|
*/
|
||||||
|
public suspend fun Plc4XDevice.read(plc4xProperty: Plc4xProperty): Meta = with(plc4xProperty) {
|
||||||
|
require(connection.metadata.isReadSupported) {"Read actions are not supported on connections"}
|
||||||
|
val request = connection.readRequestBuilder().request().build()
|
||||||
|
val response = request.execute().await()
|
||||||
|
response.throwOnFail()
|
||||||
|
response.readProperty()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send write request and suspend until it finishes. Throw a [PlcException] if at least one tag write fails.
|
||||||
|
*
|
||||||
|
* @throws PlcException
|
||||||
|
*/
|
||||||
|
public suspend fun Plc4XDevice.write(plc4xProperty: Plc4xProperty, value: Meta): Unit = with(plc4xProperty) {
|
||||||
|
require(connection.metadata.isWriteSupported){"Write actions are not supported on connection"}
|
||||||
|
val request: PlcWriteRequest = connection.writeRequestBuilder().writeProperty(value).build()
|
||||||
|
val response: PlcWriteResponse = request.execute().await()
|
||||||
|
response.throwOnFail()
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package space.kscience.controls.plc4x
|
||||||
|
|
||||||
|
import org.apache.plc4x.java.api.PlcConnection
|
||||||
|
import space.kscience.controls.spec.DeviceActionSpec
|
||||||
|
import space.kscience.controls.spec.DeviceBase
|
||||||
|
import space.kscience.controls.spec.DevicePropertySpec
|
||||||
|
import space.kscience.dataforge.context.Context
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
|
||||||
|
public class Plc4XDeviceBase(
|
||||||
|
context: Context,
|
||||||
|
meta: Meta,
|
||||||
|
override val connection: PlcConnection,
|
||||||
|
) : Plc4XDevice, DeviceBase<Plc4XDevice>(context, meta) {
|
||||||
|
override val properties: Map<String, DevicePropertySpec<Plc4XDevice, *>>
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
override val actions: Map<String, DeviceActionSpec<Plc4XDevice, *, *>> = emptyMap()
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
|
|
||||||
public interface Plc4xProperty {
|
public interface Plc4xProperty {
|
||||||
|
|
||||||
|
public val keys: Set<String>
|
||||||
|
|
||||||
public fun PlcReadRequest.Builder.request(): PlcReadRequest.Builder
|
public fun PlcReadRequest.Builder.request(): PlcReadRequest.Builder
|
||||||
|
|
||||||
public fun PlcReadResponse.readProperty(): Meta
|
public fun PlcReadResponse.readProperty(): Meta
|
||||||
@ -15,17 +17,23 @@ public interface Plc4xProperty {
|
|||||||
public fun PlcWriteRequest.Builder.writeProperty(meta: Meta): PlcWriteRequest.Builder
|
public fun PlcWriteRequest.Builder.writeProperty(meta: Meta): PlcWriteRequest.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DefaultPlc4xProperty(
|
private class DefaultPlc4xProperty(
|
||||||
private val address: String,
|
private val address: String,
|
||||||
private val plcValueType: PlcValueType,
|
private val plcValueType: PlcValueType,
|
||||||
private val name: String = "@default",
|
private val name: String = "@default",
|
||||||
) : Plc4xProperty {
|
) : Plc4xProperty {
|
||||||
|
|
||||||
|
override val keys: Set<String> = setOf(name)
|
||||||
|
|
||||||
override fun PlcReadRequest.Builder.request(): PlcReadRequest.Builder =
|
override fun PlcReadRequest.Builder.request(): PlcReadRequest.Builder =
|
||||||
addTagAddress(name, address)
|
addTagAddress(name, address)
|
||||||
|
|
||||||
override fun PlcReadResponse.readProperty(): Meta =
|
override fun PlcReadResponse.readProperty(): Meta =
|
||||||
asPlcValue.toMeta()
|
getPlcValue(name).toMeta()
|
||||||
|
|
||||||
override fun PlcWriteRequest.Builder.writeProperty(meta: Meta): PlcWriteRequest.Builder =
|
override fun PlcWriteRequest.Builder.writeProperty(meta: Meta): PlcWriteRequest.Builder =
|
||||||
addTagAddress(name, address, meta.toPlcValue(plcValueType))
|
addTagAddress(name, address, meta.toPlcValue(plcValueType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun Plc4xProperty(address: String, plcValueType: PlcValueType, name: String = "@default"): Plc4xProperty =
|
||||||
|
DefaultPlc4xProperty(address, plcValueType, name)
|
@ -84,24 +84,24 @@ private fun Context.launchPidDevice(
|
|||||||
|
|
||||||
showDashboard {
|
showDashboard {
|
||||||
plot {
|
plot {
|
||||||
plotNumberState(context, state, maxAge = maxAge) {
|
plotNumberState(context, state, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
name = "real position"
|
name = "real position"
|
||||||
}
|
}
|
||||||
plotDeviceProperty(device.pid, Regulator.position.name, maxAge = maxAge) {
|
plotDeviceProperty(device.pid, Regulator.position.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
name = "read position"
|
name = "read position"
|
||||||
}
|
}
|
||||||
|
|
||||||
plotDeviceProperty(device.pid, Regulator.target.name, maxAge = maxAge) {
|
plotDeviceProperty(device.pid, Regulator.target.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
name = "target"
|
name = "target"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plot {
|
plot {
|
||||||
plotDeviceProperty(device.start, LimitSwitch.locked.name, maxAge = maxAge) {
|
plotDeviceProperty(device.start, LimitSwitch.locked.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
name = "start measured"
|
name = "start measured"
|
||||||
mode = ScatterMode.markers
|
mode = ScatterMode.markers
|
||||||
}
|
}
|
||||||
plotDeviceProperty(device.end, LimitSwitch.locked.name, maxAge = maxAge) {
|
plotDeviceProperty(device.end, LimitSwitch.locked.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
name = "end measured"
|
name = "end measured"
|
||||||
mode = ScatterMode.markers
|
mode = ScatterMode.markers
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user