Skip to content

Commit

Permalink
ioc now successfully runs
Browse files Browse the repository at this point in the history
  • Loading branch information
evalott100 committed Oct 16, 2024
1 parent 02dafb4 commit 6000568
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 222 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ classifiers = [
]
description = "A softioc to control a PandABlocks-FPGA."
dependencies = [
"fastcs~=0.6.0",
"fastcs@git+https://github.com/DiamondLightSource/FastCS@panda-conversion-improvements",
"pandablocks~=0.10.0",
"numpy<2", # until https://github.com/mdavidsaver/p4p/issues/145 is fixed
"pydantic>2",
Expand Down
6 changes: 5 additions & 1 deletion src/fastcs_pandablocks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from fastcs.backends.epics.backend import EpicsBackend
from fastcs.backends.epics.gui import EpicsGUIFormat
from fastcs.backends.epics.ioc import EpicsIOCOptions, PvNamingConvention

from ._version import __version__
from .gui import PandaGUIOptions
Expand All @@ -21,7 +22,10 @@ def ioc(
clear_bobfiles: bool = False,
):
controller = PandaController(hostname, poll_period)
backend = EpicsBackend(controller, pv_prefix=str(prefix))
epics_ioc_options = EpicsIOCOptions(
terminal=True, pv_naming_convention=PvNamingConvention.CAPITALIZED
)
backend = EpicsBackend(controller, pv_prefix=str(prefix), options=epics_ioc_options)

if clear_bobfiles and not screens_directory:
raise ValueError("`clear_bobfiles` is True with no `screens_directory`")
Expand Down
3 changes: 1 addition & 2 deletions src/fastcs_pandablocks/gui.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from fastcs.backends.epics.gui import EpicsGUIOptions


class PandaGUIOptions(EpicsGUIOptions):
...
class PandaGUIOptions(EpicsGUIOptions): ...
66 changes: 40 additions & 26 deletions src/fastcs_pandablocks/panda/blocks.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from collections.abc import Generator

from fastcs.attributes import AttrR, AttrRW, AttrW
from fastcs.controller import SubController
from pandablocks.responses import BlockInfo

from fastcs_pandablocks.types import EpicsName, PandaName, ResponseType
from fastcs_pandablocks.types import AttrType, EpicsName, PandaName, ResponseType

from .fields import FIELD_TYPE_TO_FASTCS_TYPE, FieldType


class Block(SubController):
class BlockController(SubController):
fields: dict[str, FieldType]

def __init__(
Expand All @@ -25,17 +26,24 @@ def __init__(
self.fields = {}

for field_raw_name, field_info in raw_fields.items():
field_panda_name = PandaName(field=field_raw_name)
print(field_raw_name)
field_panda_name = self.panda_name + PandaName(field=field_raw_name)

field = FIELD_TYPE_TO_FASTCS_TYPE[field_info.type][field_info.subtype](
field_panda_name, field_info.description
# TODO make type safe after match statment
field_panda_name,
field_info, # type: ignore
)
self.fields[field_raw_name] = field
self.register_sub_controller(field_panda_name.attribute_name, field)
if field.block_attribute:
setattr(self, *field.block_attribute)
if field.sub_field_controller:
self.register_sub_controller(
field_panda_name.attribute_name, field.sub_field_controller
)


class Blocks:
_blocks: dict[str, dict[int | None, Block]]
_blocks: dict[str, dict[int | None, BlockController]]
epics_prefix: EpicsName

def __init__(self):
Expand All @@ -51,11 +59,15 @@ def parse_introspected_data(
):
iterator = (
range(1, block_info.number + 1)
if block_info.number > 1 else iter([None,])
if block_info.number > 1
else iter(
[
None,
]
)
)
self._blocks[block_name] = {
number:
Block(
number: BlockController(
PandaName(block=block_name, block_number=number),
block_info.number,
block_info.description,
Expand All @@ -65,26 +77,25 @@ def parse_introspected_data(
}

async def update_field_value(self, panda_name: PandaName, value: str):
assert panda_name.block
assert panda_name.field
field = (
self._blocks[panda_name.block][panda_name.block_number].fields[panda_name.field]
)
if panda_name.sub_field:
field = field.sub_fields[panda_name.sub_field]
await field.update_value(value)
attribute = self[panda_name]

if isinstance(attribute, AttrW):
await attribute.process(value)
elif isinstance(attribute, (AttrRW | AttrR)):
await attribute.set(value)
else:
raise RuntimeError(f"Couldn't find panda field for {panda_name}.")

def flattened_attribute_tree(
self
) -> Generator[tuple[str, Block], None, None]:
self,
) -> Generator[tuple[str, BlockController], None, None]:
for blocks in self._blocks.values():
for block in blocks.values():
yield (block.panda_name.attribute_name, block)

def __getitem__(
self,
name: EpicsName | PandaName
) -> dict[int | None, Block] | Block | FieldType:
self, name: EpicsName | PandaName
) -> dict[int | None, BlockController] | BlockController | AttrType:
if name.block is None:
raise ValueError(f"Cannot find block for name {name}.")
blocks = self._blocks[name.block]
Expand All @@ -94,6 +105,9 @@ def __getitem__(
if name.field is None:
return block
field = block.fields[name.field]
if name.sub_field is None:
return field
return field.sub_fields[name.sub_field]
if not name.sub_field:
assert field.block_attribute
return field.block_attribute.attribute

sub_field = getattr(field.sub_field_controller, name.sub_field)
return sub_field
23 changes: 16 additions & 7 deletions src/fastcs_pandablocks/panda/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from fastcs.controller import Controller
from fastcs.wrappers import scan

from fastcs_pandablocks import DEFAULT_POLL_PERIOD
from fastcs_pandablocks.types import PandaName

from .blocks import Blocks
Expand All @@ -12,16 +11,16 @@

class PandaController(Controller):
def __init__(self, hostname: str, poll_period: float) -> None:
super().__init__()
self._raw_panda = RawPanda(hostname)
self._blocks = Blocks()
self.is_connected = False

# TODO https://github.com/DiamondLightSource/FastCS/issues/62
#self.fastcs_method = Scan(self.update(), poll_period)

async def initialise(self) -> None: ...
super().__init__()

async def connect(self) -> None:
if self.is_connected:
return

await self._raw_panda.connect()

assert self._raw_panda.blocks
Expand All @@ -32,7 +31,17 @@ async def connect(self) -> None:
for attr_name, controller in self._blocks.flattened_attribute_tree():
self.register_sub_controller(attr_name, controller)

@scan(DEFAULT_POLL_PERIOD) # TODO https://github.com/DiamondLightSource/FastCS/issues/62
self.is_connected = True

async def initialise(self) -> None:
"""
We connect in initialise since FastCS doesn't connect until
it's already parsed sub controllers.
"""
await self.connect()

# TODO https://github.com/DiamondLightSource/FastCS/issues/62
@scan(0.1)
async def update(self):
await self._raw_panda.get_changes()
assert self._raw_panda.changes
Expand Down
Loading

0 comments on commit 6000568

Please sign in to comment.