Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eiger FastCS: Use PVI information to fill in PVs #551

Open
coretl opened this issue Sep 2, 2024 · 1 comment
Open

Eiger FastCS: Use PVI information to fill in PVs #551

coretl opened this issue Sep 2, 2024 · 1 comment

Comments

@coretl
Copy link
Collaborator

coretl commented Sep 2, 2024

          As soon as PVI datastructures are published over PVA then this file will drastically change to something like:
class EigerDriverIO(Device):
    bit_depth: SignalR[int]
    stale_parameters: SignalR[bool]
    ...

It will also only need to include the signals that are needed at static analysis time, at runtime then all the extras (like beam_centre_x, etc) will be filled in automatically.

This will also mean that the class structure and ophyd attribute names will have to exactly match those in PVI.

For this reason I suggest we do this soon, and @GDYendell is going to start looking at this now

Originally posted by @coretl in #528 (comment)

@DominicOram
Copy link
Contributor

Following #557 (comment) I think we can now do this.

coretl added a commit that referenced this issue Oct 30, 2024
Rewrite the type support, and use a plugin `Connector` architecture to support reconnection for PVI and Tango.

Fixes #472, fixes #562, fixes #535, fixes #505, fixes #373, fixes #601 

Required for #551

# Breaking changes
## pvi structure changes
Structure now read from `.value` rather than `.pvi`. Supported in FastCS. Requires at least PandABlocks-ioc 0.10.0
## `StrictEnum` is now requried for all strictly checked `Enums`
```python
# old
from enum import Enum
class MyEnum(str, Enum):
    ONE = "one"
    TWO = "two"
# new
from ophyd_async.core import StrictEnum
class MyEnum(StrictEnum):
    ONE = "one"
    TWO = "two"
```
## `SubsetEnum` is now an `Enum` subclass:
```python
from ophyd_async.core import SubsetEnum
# old
MySubsetEnum = SubsetEnum["one", "two"]
# new
class MySubsetEnum(SubsetEnum):
    ONE = "one"
    TWO = "two"
```
## Use python primitives for scalar types instead of numpy types
```python
# old
import numpy as np
x = epics_signal_rw(np.int32, "PV")
# new
x = epics_signal_rw(int, "PV")
```
## Use `Array1D` for 1D arrays instead of `npt.NDArray`
```python
import numpy as np
# old
import numpy.typing as npt
x = epics_signal_rw(npt.NDArray[np.int32], "PV")
# new
from ophyd_async.core import Array1D
x = epics_signal_rw(Array1D[np.int32], "PV")
```
## Use `Sequence[str]` for arrays of strings instead of `npt.NDArray[np.str_]`
```python
import numpy as np
# old
import numpy.typing as npt
x = epics_signal_rw(npt.NDArray[np.str_], "PV")
# new
from collections.abc import Sequence
x = epics_signal_rw(Sequence[str], "PV")
```
## `MockSignalBackend` requires a real backend
```python
# old
fake_set_signal = SignalRW(MockSignalBackend(float))
# new
fake_set_signal = soft_signal_rw(float)
await fake_set_signal.connect(mock=True)
```
## `get_mock_put` is no longer passed timeout as it is handled in `Signal`
```python
# old
get_mock_put(driver.capture).assert_called_once_with(Writing.ON, wait=ANY, timeout=ANY)
# new
get_mock_put(driver.capture).assert_called_once_with(Writing.ON, wait=ANY)
```
## `super().__init__` required for `Device` subclasses
```python
# old
class MyDevice(Device):
    def __init__(self, name: str = ""):
        self.signal, self.backend_put = soft_signal_r_and_setter(int)
# new
class MyDevice(Device):
    def __init__(self, name: str = ""):
        self.signal, self.backend_put = soft_signal_r_and_setter(int)
        super().__init__(name=name)
```
## Arbitrary `BaseModel`s not supported, pending use cases for them
The `Table` type has been suitable for everything we have seen so far, if you need an arbitrary `BaseModel` subclass then please make an issue
## Child `Device`s set parent on attach, and can't be public children of more than one parent
```python
class SourceDevice(Device):
    def __init__(self, name: str = ""):
        self.signal = soft_signal_rw(int)
        super().__init__(name=name)

# old
class ReferenceDevice(Device):
    def __init__(self, signal: SignalRW[int], name: str = ""):
        self.signal = signal
        super().__init__(name=name)

    def set(self, value) -> AsyncStatus:
        return self.signal.set(value + 1)
# new
from ophyd_async.core import Reference

class ReferenceDevice(Device):
    def __init__(self, signal: SignalRW[int], name: str = ""):
        self._signal_ref = Reference(signal)
        super().__init__(name=name)

    def set(self, value) -> AsyncStatus:
        return self._signal_ref().set(value + 1)
```
ZohebShaikh pushed a commit that referenced this issue Nov 14, 2024
Rewrite the type support, and use a plugin `Connector` architecture to support reconnection for PVI and Tango.

Fixes #472, fixes #562, fixes #535, fixes #505, fixes #373, fixes #601

Required for #551

Structure now read from `.value` rather than `.pvi`. Supported in FastCS. Requires at least PandABlocks-ioc 0.10.0
```python
from enum import Enum
class MyEnum(str, Enum):
    ONE = "one"
    TWO = "two"
from ophyd_async.core import StrictEnum
class MyEnum(StrictEnum):
    ONE = "one"
    TWO = "two"
```
```python
from ophyd_async.core import SubsetEnum
MySubsetEnum = SubsetEnum["one", "two"]
class MySubsetEnum(SubsetEnum):
    ONE = "one"
    TWO = "two"
```
```python
import numpy as np
x = epics_signal_rw(np.int32, "PV")
x = epics_signal_rw(int, "PV")
```
```python
import numpy as np
import numpy.typing as npt
x = epics_signal_rw(npt.NDArray[np.int32], "PV")
from ophyd_async.core import Array1D
x = epics_signal_rw(Array1D[np.int32], "PV")
```
```python
import numpy as np
import numpy.typing as npt
x = epics_signal_rw(npt.NDArray[np.str_], "PV")
from collections.abc import Sequence
x = epics_signal_rw(Sequence[str], "PV")
```
```python
fake_set_signal = SignalRW(MockSignalBackend(float))
fake_set_signal = soft_signal_rw(float)
await fake_set_signal.connect(mock=True)
```
```python
get_mock_put(driver.capture).assert_called_once_with(Writing.ON, wait=ANY, timeout=ANY)
get_mock_put(driver.capture).assert_called_once_with(Writing.ON, wait=ANY)
```
```python
class MyDevice(Device):
    def __init__(self, name: str = ""):
        self.signal, self.backend_put = soft_signal_r_and_setter(int)
class MyDevice(Device):
    def __init__(self, name: str = ""):
        self.signal, self.backend_put = soft_signal_r_and_setter(int)
        super().__init__(name=name)
```
The `Table` type has been suitable for everything we have seen so far, if you need an arbitrary `BaseModel` subclass then please make an issue
```python
class SourceDevice(Device):
    def __init__(self, name: str = ""):
        self.signal = soft_signal_rw(int)
        super().__init__(name=name)

class ReferenceDevice(Device):
    def __init__(self, signal: SignalRW[int], name: str = ""):
        self.signal = signal
        super().__init__(name=name)

    def set(self, value) -> AsyncStatus:
        return self.signal.set(value + 1)
from ophyd_async.core import Reference

class ReferenceDevice(Device):
    def __init__(self, signal: SignalRW[int], name: str = ""):
        self._signal_ref = Reference(signal)
        super().__init__(name=name)

    def set(self, value) -> AsyncStatus:
        return self._signal_ref().set(value + 1)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants