Compare commits

...

2 Commits

7 changed files with 29 additions and 26 deletions

View File

@ -124,5 +124,5 @@ public fun Device.getAllProperties(): Meta = Meta {
/**
* Subscribe on property changes for the whole device
*/
public fun Device.onPropertyChange(callback: suspend PropertyChangedMessage.() -> Unit): Job =
messageFlow.filterIsInstance<PropertyChangedMessage>().onEach(callback).launchIn(this)
public fun Device.onPropertyChange(scope: CoroutineScope = this, callback: suspend PropertyChangedMessage.() -> Unit): Job =
messageFlow.filterIsInstance<PropertyChangedMessage>().onEach(callback).launchIn(scope)

View File

@ -87,7 +87,7 @@ public abstract class DeviceBase<D : Device>(
/**
* Update logical property state and notify listeners
*/
protected suspend fun updateLogical(propertyName: String, value: Meta?) {
protected suspend fun propertyChanged(propertyName: String, value: Meta?) {
if (value != logicalState[propertyName]) {
stateLock.withLock {
logicalState[propertyName] = value
@ -99,10 +99,10 @@ public abstract class DeviceBase<D : Device>(
}
/**
* Update logical state using given [spec] and its convertor
* Notify the device that a property with [spec] value is changed
*/
public suspend fun <T> updateLogical(spec: DevicePropertySpec<D, T>, value: T) {
updateLogical(spec.name, spec.converter.objectToMeta(value))
protected suspend fun <T> propertyChanged(spec: DevicePropertySpec<D, T>, value: T) {
propertyChanged(spec.name, spec.converter.objectToMeta(value))
}
/**
@ -112,7 +112,7 @@ public abstract class DeviceBase<D : Device>(
override suspend fun readProperty(propertyName: String): Meta {
val spec = properties[propertyName] ?: error("Property with name $propertyName not found")
val meta = spec.readMeta(self) ?: error("Failed to read property $propertyName")
updateLogical(propertyName, meta)
propertyChanged(propertyName, meta)
return meta
}
@ -122,7 +122,7 @@ public abstract class DeviceBase<D : Device>(
public suspend fun readPropertyOrNull(propertyName: String): Meta? {
val spec = properties[propertyName] ?: return null
val meta = spec.readMeta(self) ?: return null
updateLogical(propertyName, meta)
propertyChanged(propertyName, meta)
return meta
}
@ -137,13 +137,18 @@ public abstract class DeviceBase<D : Device>(
override suspend fun writeProperty(propertyName: String, value: Meta): Unit {
when (val property = properties[propertyName]) {
null -> {
//If there is a physical property with a given name, invalidate logical property and write physical one
updateLogical(propertyName, value)
//If there are no physical properties with given name, write a logical one.
propertyChanged(propertyName, value)
}
is WritableDevicePropertySpec -> {
//if there is a writeable property with a given name, invalidate logical and write physical
invalidate(propertyName)
property.writeMeta(self, value)
// perform read after writing if the writer did not set the value
if (logicalState[propertyName] == null) {
readPropertyOrNull(propertyName)
}
}
else -> {

View File

@ -115,6 +115,7 @@ public fun <D : Device, T> D.propertyFlow(spec: DevicePropertySpec<D, T>): Flow<
*/
public fun <D : Device, T> D.onPropertyChange(
spec: DevicePropertySpec<D, T>,
scope: CoroutineScope = this,
callback: suspend PropertyChangedMessage.(T) -> Unit,
): Job = messageFlow
.filterIsInstance<PropertyChangedMessage>()
@ -124,15 +125,16 @@ public fun <D : Device, T> D.onPropertyChange(
if (newValue != null) {
change.callback(newValue)
}
}.launchIn(this)
}.launchIn(scope)
/**
* Call [callback] on initial property value and each value change
*/
public fun <D : Device, T> D.useProperty(
spec: DevicePropertySpec<D, T>,
scope: CoroutineScope = this,
callback: suspend (T) -> Unit,
): Job = launch {
): Job = scope.launch {
callback(read(spec))
messageFlow
.filterIsInstance<PropertyChangedMessage>()

View File

@ -22,7 +22,7 @@ public val MetaConverter.Companion.unit: MetaConverter<Unit> get() = UnitMetaCon
@OptIn(InternalDeviceAPI::class)
public abstract class DeviceSpec<D : Device> {
//initializing meta property for everyone
//initializing the metadata property for everyone
private val _properties = hashMapOf<String, DevicePropertySpec<D, *>>(
DeviceMetaPropertySpec.name to DeviceMetaPropertySpec
)

View File

@ -183,10 +183,6 @@ public fun ModbusDevice.writeHoldingRegisters(address: Int, buffer: ByteBuffer):
return writeHoldingRegisters(address, array)
}
public fun ModbusDevice.writeShortRegister(address: Int, value: Short) {
master.writeSingleRegister(address, SimpleInputRegister(value.toInt()))
}
public fun ModbusDevice.modbusRegister(
address: Int,
): ReadWriteProperty<ModbusDevice, Short> = object : ReadWriteProperty<ModbusDevice, Short> {

View File

@ -49,16 +49,16 @@ class MksPdr900Device(context: Context, meta: Meta) : DeviceBySpec<MksPdr900Devi
if (powerOnValue) {
val ans = talk("FP!ON")
if (ans == "ON") {
updateLogical(powerOn, true)
propertyChanged(powerOn, true)
} else {
updateLogical(error, "Failed to set power state")
propertyChanged(error, "Failed to set power state")
}
} else {
val ans = talk("FP!OFF")
if (ans == "OFF") {
updateLogical(powerOn, false)
propertyChanged(powerOn, false)
} else {
updateLogical(error, "Failed to set power state")
propertyChanged(error, "Failed to set power state")
}
}
}
@ -68,13 +68,13 @@ class MksPdr900Device(context: Context, meta: Meta) : DeviceBySpec<MksPdr900Devi
invalidate(error)
return if (answer.isNullOrEmpty()) {
// updateState(PortSensor.CONNECTED_STATE, false)
updateLogical(error, "No connection")
propertyChanged(error, "No connection")
null
} else {
val res = answer.toDouble()
if (res <= 0) {
updateLogical(powerOn, false)
updateLogical(error, "No power")
propertyChanged(powerOn, false)
propertyChanged(error, "No power")
null
} else {
res

View File

@ -172,7 +172,7 @@ class PiMotionMasterDevice(
//Update port
//address = portSpec.node
port = portFactory(portSpec, context)
updateLogical(connected, true)
propertyChanged(connected, true)
// connector.open()
//Initialize axes
val idn = read(identity)
@ -196,7 +196,7 @@ class PiMotionMasterDevice(
it.close()
}
port = null
updateLogical(connected, false)
propertyChanged(connected, false)
}