Skip to content

Commit

Permalink
WIP - Dynamic tables
Browse files Browse the repository at this point in the history
  • Loading branch information
GDYendell committed Dec 21, 2022
1 parent 1bc15bf commit 0b6c418
Show file tree
Hide file tree
Showing 10 changed files with 529 additions and 0 deletions.
123 changes: 123 additions & 0 deletions schemas/pvi.producer.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@
},
{
"$ref": "#/definitions/AsynFloat64Waveform"
},
{
"$ref": "#/definitions/AsynTable"
}
]
},
Expand Down Expand Up @@ -7189,6 +7192,126 @@
],
"additionalProperties": false
},
"AsynTable": {
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "AsynTable",
"default": "AsynTable"
},
"name": {
"type": "string",
"pattern": "([A-Z][a-z0-9]*)*$",
"description": "PascalCase name to uniquely identify"
},
"description": {
"type": "string",
"description": "Description of what this Parameter is for"
},
"index_name": {
"type": [
"string",
"null"
],
"description": "Override name of index variable in source code (defaults to name)",
"default": null
},
"drv_info": {
"type": [
"string",
"null"
],
"pattern": "^\\S{1,40}$",
"description": "Info string for drvUserCreate for dynamically created parameters",
"default": null
},
"access": {
"description": "What access does the user have. One of:\n\n - R: Read only value that cannot be set. E.g. chipTemperature on a detector,\n or isHomed for a motor\n - W: Write only value that can be written to, but there is no current value.\n E.g. reboot on a detector, or overwriteCurrentPosition for a motor\n - RW: Read and Write value that can be written to and read back.\n E.g. acquireTime on a detector, or velocity of a motor\n ",
"default": "RW",
"allOf": [
{
"$ref": "#/definitions/Access"
}
]
},
"demand_auto_updates": {
"type": "boolean",
"description": "Should demand update when readback changes?",
"default": false
},
"read_record_suffix": {
"type": [
"string",
"null"
],
"description": "The read record suffix, if not given then use $(name)_RBV",
"default": null
},
"write_record_suffix": {
"type": [
"string",
"null"
],
"description": "The write record suffix, if not given then use $(name)",
"default": null
},
"display_form": {
"anyOf": [
{
"$ref": "#/definitions/DisplayForm"
},
{
"type": "null"
}
],
"description": "Display form for numeric/array fields",
"default": null
},
"initial": {
"default": null
},
"read_widget": {
"anyOf": [
{
"$ref": "#/definitions/ReadWidget"
},
{
"type": "null"
}
],
"description": "Widget to use for read record",
"default": {
"type": "TableRead",
"widgets": []
}
},
"write_widget": {
"anyOf": [
{
"$ref": "#/definitions/WriteWidget"
},
{
"type": "null"
}
],
"description": "Widget to use for write record",
"default": {
"type": "TableWrite",
"widgets": []
}
},
"record_fields": {
"type": "string",
"default": ""
}
},
"required": [
"name",
"description"
],
"additionalProperties": false
},
"AsynParameterGroup": {
"type": "object",
"properties": {
Expand Down
4 changes: 4 additions & 0 deletions src/pvi/_format/aps.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ def format(self, device: Device, prefix: str, path: Path):
text_write_cls=PVWidgetFactory.from_template(
template, search='"TextWrite"', chan="pv"
),
# Cannot handle dynamic tables so insert a label with the PV name
table_cls=PVWidgetFactory.from_template(
template, search='"Label"', textix="pv"
),
action_button_cls=ActionFactory.from_template(
template, search='"SignalX"', label="label", chan="pv"
),
Expand Down
8 changes: 8 additions & 0 deletions src/pvi/_format/dls.bob
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,12 @@
<height>40</height>
<tooltip>$(actions)</tooltip>
</widget>
<widget type="table" version="2.0.0">
<name>Table</name>
<pv_name>pva://Table</pv_name>
<x>300</x>
<y>300</y>
<width>200</width>
<height>100</height>
</widget>
</display>
7 changes: 7 additions & 0 deletions src/pvi/_format/dls.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ def format_edl(self, device: Device, prefix: str, path: Path):
text_write_cls=PVWidgetFactory.from_template(
template, search='"TextWrite"', controlPv="pv"
),
# Cannot handle dynamic tables so insert a label with the PV name
table_cls=PVWidgetFactory.from_template(
template, search='"Label"', value="pv"
),
action_button_cls=ActionFactory.from_template(
template,
search='"SignalX"',
Expand Down Expand Up @@ -197,6 +201,9 @@ def format_bob(self, device: Device, prefix: str, path: Path):
text_write_cls=PVWidgetFactory.from_template(
template, search="TextEntry", pv_name="pv"
),
table_cls=PVWidgetFactory.from_template(
template, search="Table", pv_name="pv"
),
action_button_cls=ActionFactory.from_template(
template, search="ActionButton", text="label", pv_name="pv"
),
Expand Down
5 changes: 5 additions & 0 deletions src/pvi/_format/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
SignalW,
SignalX,
SubScreen,
TableRead,
TextRead,
TextWrite,
Tree,
Expand Down Expand Up @@ -270,6 +271,7 @@ class ScreenWidgets(Generic[T]):
check_box_cls: Type[PVWidgetFactory[T]]
combo_box_cls: Type[PVWidgetFactory[T]]
text_write_cls: Type[PVWidgetFactory[T]]
table_cls: Type[PVWidgetFactory[T]]
action_button_cls: Type[ActionFactory[T]]
sub_screen_cls: Type[SubScreenFactory[T]]

Expand Down Expand Up @@ -299,6 +301,7 @@ def pv_widget(
CheckBox: self.check_box_cls,
ComboBox: self.combo_box_cls,
TextWrite: self.text_write_cls,
TableRead: self.table_cls,
}
if isinstance(widget, (TextRead, TextWrite)):
bounds.h *= widget.lines
Expand Down Expand Up @@ -850,6 +853,8 @@ def set(
for item, value in properties.items():
if item == "file":
value = f"{value}.bob" # Must include file extension
elif t.attrib.get("type", "") == "table" and item == "pv_name":
value = f"pva://{value}" # Must include pva prefix
try:
# Iterate tree to find item and replace value
list(t_copy.iter(tag=item))[0].text = str(value)
Expand Down
17 changes: 17 additions & 0 deletions src/pvi/_produce/asyn.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
SignalR,
SignalRW,
SignalW,
TableRead,
TableWrite,
TextRead,
TextWrite,
Tree,
Expand Down Expand Up @@ -279,6 +281,21 @@ class AsynFloat64Waveform(AsynWaveform):
] = WaveformRecordPair()


@dataclass
class AsynTable(AsynParameter):
"""An NTTable"""

# TODO: What should type_strings and record_fields be for an NTTable? Does
# it even need to be written in yaml or does it only need to be created from code?
type_strings = TypeStrings("", "", "")
record_fields = Annotated[ # type: ignore
RecordPair, desc("Waveform record fields")
] = RecordPair.for_record_types("", "")

read_widget: AReadWidget = TableRead([])
write_widget: AWriteWidget = TableWrite([])


def find_components(yaml_name: str, yaml_paths: List[Path]) -> Tree[AsynParameter]:
if yaml_name == "asynPortDriver":
return [] # asynPortDriver is the most base class and has no parameters
Expand Down
19 changes: 19 additions & 0 deletions tests/produce_format/input/dynamic_table.pvi.producer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# yaml-language-server: $schema=../../../schemas/pvi.producer.schema.json
type: AsynProducer
label: Table
prefix: $(P)$(R)
asyn_port: $(PORT)
address: $(ADDR=0)
timeout: $(TIMEOUT=1)
parent: asynPortDriver
parameters:
- type: AsynBinary
name: Binary
description: Binary
drv_info: BINARY
access: R
index_name: Binary
- type: AsynTable
name: BigTable
description: NTTable
access: R
Loading

0 comments on commit 0b6c418

Please sign in to comment.