-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
started the structure and async iterator parsing the panda
- Loading branch information
1 parent
c4bcf96
commit 6073cfc
Showing
10 changed files
with
336 additions
and
7 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
"""Contains logic relevant to fastcs. Will use `fastcs_pandablocks.panda`.""" | ||
|
||
|
||
from pathlib import Path | ||
|
||
from fastcs.backends.epics.backend import EpicsBackend | ||
|
||
from .gui import PandaGUIOptions | ||
from .controller import PandaController | ||
from fastcs_pandablocks.types import EpicsName | ||
|
||
|
||
def ioc( | ||
panda_hostname: str, | ||
pv_prefix: EpicsName, | ||
screens_directory: Path | None, | ||
clear_bobfiles: bool = False, | ||
): | ||
controller = PandaController(panda_hostname) | ||
backend = EpicsBackend(controller, pv_prefix=str(pv_prefix)) | ||
|
||
if clear_bobfiles and not screens_directory: | ||
raise ValueError("`clear_bobfiles` is True with no `screens_directory`") | ||
|
||
if screens_directory: | ||
if not screens_directory.is_dir(): | ||
raise ValueError( | ||
f"`screens_directory` {screens_directory} is not a directory" | ||
) | ||
backend.create_gui( | ||
PandaGUIOptions() | ||
) | ||
|
||
backend.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# TODO: tackle after I have a MVP of the panda part. | ||
from fastcs.controller import Controller | ||
from fastcs.datatypes import Bool, Float, Int, String | ||
|
||
|
||
class PandaController(Controller): | ||
def __init__(self, hostname: str) -> None: | ||
super().__init__() | ||
|
||
async def initialise(self) -> None: | ||
pass | ||
|
||
async def connect(self) -> None: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from fastcs.backends.epics.gui import EpicsGUIOptions | ||
|
||
class PandaGUIOptions(EpicsGUIOptions): | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Contains the logic relevant to the Panda's operation.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
""" | ||
Over the years we've had to add little adjustments on top of the `BlockInfo`, `BlockAndFieldInfo`, etc. | ||
This method has a `RawPanda` which handles all the io with the client. | ||
""" | ||
|
||
import asyncio | ||
from pandablocks.asyncio import AsyncioClient | ||
from pandablocks.commands import ( | ||
ChangeGroup, | ||
Changes, | ||
GetBlockInfo, | ||
GetChanges, | ||
GetFieldInfo, | ||
) | ||
from pandablocks.responses import ( | ||
BitMuxFieldInfo, | ||
BitOutFieldInfo, | ||
BlockInfo, | ||
Changes, | ||
EnumFieldInfo, | ||
ExtOutBitsFieldInfo, | ||
ExtOutFieldInfo, | ||
FieldInfo, | ||
PosMuxFieldInfo, | ||
PosOutFieldInfo, | ||
ScalarFieldInfo, | ||
SubtypeTimeFieldInfo, | ||
TableFieldInfo, | ||
TimeFieldInfo, | ||
UintFieldInfo, | ||
) | ||
from typing import Union | ||
|
||
ResponseType = Union[ | ||
BitMuxFieldInfo, | ||
BitOutFieldInfo, | ||
EnumFieldInfo, | ||
ExtOutBitsFieldInfo, | ||
ExtOutFieldInfo, | ||
FieldInfo, | ||
PosMuxFieldInfo, | ||
PosOutFieldInfo, | ||
ScalarFieldInfo, | ||
SubtypeTimeFieldInfo, | ||
TableFieldInfo, | ||
TimeFieldInfo, | ||
UintFieldInfo, | ||
] | ||
|
||
class RawPanda: | ||
_blocks: dict[str, BlockInfo] | None = None | ||
_metadata: tuple[Changes] | None = None | ||
|
||
_responses: list[dict[str, ResponseType]] | None = None | ||
_changes: Changes | None = None | ||
|
||
def __init__(self, host: str): | ||
self._client = AsyncioClient(host) | ||
|
||
async def connect(self): await self._client.connect() | ||
|
||
async def disconnect(self): await self._client.close() | ||
|
||
async def introspect(self): | ||
self._blocks = await self._client.send(GetBlockInfo()) | ||
self._responses = await asyncio.gather( | ||
*[self._client.send(GetFieldInfo(block)) for block in self._blocks], | ||
) | ||
self._metadata = await self._client.send(GetChanges(ChangeGroup.ALL, True)), | ||
|
||
async def get_changes(self): | ||
self._changes = await self._client.send(GetChanges(ChangeGroup.ALL, False)) | ||
|
||
|
||
async def _sync_with_panda(self): | ||
if not self._client.is_connected(): | ||
await self.connect() | ||
await self.introspect() | ||
|
||
async def _ensure_connected(self): | ||
if not self._blocks: | ||
await self._sync_with_panda() | ||
|
||
async def __aenter__(self): | ||
await self._sync_with_panda() | ||
return self | ||
|
||
async def __aexit__(self, exc_type, exc, tb): | ||
await self._ensure_connected() | ||
await self.disconnect() | ||
|
||
def __aiter__(self): | ||
return self | ||
|
||
async def __anext__(self): | ||
await self._ensure_connected() | ||
return await self.get_changes() | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
from dataclasses import dataclass | ||
import re | ||
from pydantic import BaseModel | ||
from typing import Literal | ||
|
||
from pydantic import BaseModel | ||
|
||
|
||
# Dataclasses for names | ||
|
||
@dataclass | ||
class _Name: | ||
_name: str | ||
|
||
def __str__(self): | ||
return str(self._name) | ||
|
||
class PandaName(_Name): | ||
def to_epics_name(self): | ||
return EpicsName(self._name.replace(".", ":")) | ||
|
||
class EpicsName(_Name): | ||
def to_panda_name(self): | ||
return PandaName(self._name.replace(":", ".")) | ||
|
||
def to_pvi_name(self): | ||
relevant_section = self._name.split(":")[-1] | ||
words = relevant_section.replace("-", "_").split("_") | ||
capitalised_word = "".join(word.capitalize() for word in words) | ||
|
||
# We don't want to allow any non-alphanumeric characters. | ||
formatted_word = re.search(r"[A-Za-z0-9]+", capitalised_word) | ||
assert formatted_word | ||
|
||
return PviName(formatted_word.group()) | ||
|
||
class PviName(_Name): | ||
... | ||
|
||
|
||
|
||
Field_T = Literal[ | ||
"time", | ||
"bit_out", | ||
"pos_out", | ||
"ext_out", | ||
"bit_mux", | ||
"pos_mux", | ||
"param", | ||
"read", | ||
"write", | ||
] | ||
|
||
FieldSubtype_T = Literal[ | ||
"timestamp", | ||
"samples", | ||
"bits", | ||
"uint", | ||
"int", | ||
"scalar", | ||
"bit", | ||
"action", | ||
"lut", | ||
"enum", | ||
"time", | ||
] | ||
|
||
|
||
class PandaField(BaseModel, frozen=True): | ||
"""Validates fields from the client.""" | ||
|
||
field_type: Field_T | ||
field_subtype: FieldSubtype_T | None | ||
|
||
|
||
TIME_FIELDS = { | ||
PandaField(field_type="time", field_subtype=None), | ||
} | ||
|
||
BIT_OUT_FIELDS = { | ||
PandaField(field_type="bit_out", field_subtype=None), | ||
} | ||
|
||
POS_OUT_FIELDS = { | ||
PandaField(field_type="pos_out", field_subtype=None), | ||
} | ||
|
||
EXT_OUT_FIELDS = { | ||
PandaField(field_type="ext_out", field_subtype="timestamp"), | ||
PandaField(field_type="ext_out", field_subtype="samples"), | ||
} | ||
|
||
EXT_OUT_BITS_FIELDS = { | ||
PandaField(field_type="ext_out", field_subtype="bits"), | ||
} | ||
|
||
BIT_MUX_FIELDS = { | ||
PandaField(field_type="bit_mux", field_subtype=None), | ||
} | ||
|
||
POS_MUX_FIELDS = { | ||
PandaField(field_type="pos_mux", field_subtype=None), | ||
} | ||
|
||
UINT_FIELDS = { | ||
PandaField(field_type="param", field_subtype="uint"), | ||
PandaField(field_type="read", field_subtype="uint"), | ||
PandaField(field_type="write", field_subtype="uint"), | ||
} | ||
|
||
INT_FIELDS = { | ||
PandaField(field_type="param", field_subtype="int"), | ||
PandaField(field_type="read", field_subtype="int"), | ||
PandaField(field_type="write", field_subtype="int"), | ||
} | ||
|
||
SCALAR_FIELDS = { | ||
PandaField(field_type="param", field_subtype="scalar"), | ||
PandaField(field_type="read", field_subtype="scalar"), | ||
PandaField(field_type="write", field_subtype="scalar"), | ||
} | ||
|
||
BIT_FIELDS = { | ||
PandaField(field_type="param", field_subtype="bit"), | ||
PandaField(field_type="read", field_subtype="bit"), | ||
PandaField(field_type="write", field_subtype="bit"), | ||
} | ||
|
||
ACTION_FIELDS = { | ||
PandaField(field_type="param", field_subtype="action"), | ||
PandaField(field_type="read", field_subtype="action"), | ||
PandaField(field_type="write", field_subtype="action"), | ||
} | ||
|