Skip to content

Commit

Permalink
Merge pull request #26 from evalott100/make_pv_names_consistent_with_…
Browse files Browse the repository at this point in the history
…web_gui_names

Make pv names consistent with web gui names
  • Loading branch information
evalott100 authored Sep 1, 2023
2 parents e292130 + 20bac0b commit 1f8caba
Show file tree
Hide file tree
Showing 21 changed files with 1,192 additions and 313 deletions.
15 changes: 4 additions & 11 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,12 @@
"remoteEnv": {
"DISPLAY": "${localEnv:DISPLAY}"
},
// Add the URLs of features you want added when the container is built.
"features": {
"ghcr.io/devcontainers/features/common-utils:1": {
"username": "none",
"upgradePackages": false
}
},
// Set *default* container specific settings.json values on container create.
"settings": {
"python.defaultInterpreterPath": "/venv/bin/python"
},
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "/venv/bin/python"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python",
Expand All @@ -51,4 +44,4 @@
"workspaceFolder": "${localWorkspaceFolder}",
// After the container is created, install the python project in editable form
"postCreateCommand": "pip install -e '.[dev]'"
}
}
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# The devcontainer should use the build target and run as root with podman
# or docker with user namespaces.
#
FROM python:3.11 as build
FROM python:3.10 as build

ARG PIP_OPTIONS=.

Expand All @@ -24,7 +24,7 @@ WORKDIR /context
# install python package into /venv
RUN pip install ${PIP_OPTIONS}

FROM python:3.11-slim as runtime
FROM python:3.10-slim as runtime

# Add apt-get system dependecies for runtime here if needed

Expand Down
13 changes: 8 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies = [
"numpy",
"click",
"h5py",
"softioc>=4.3.0",
"softioc>=4.4.0",
"pandablocks>=0.3.1",
"pvi>=0.5",
] # Add project dependencies here, e.g. ["click", "numpy"]
Expand All @@ -37,7 +37,7 @@ dev = [
"pre-commit",
"p4p",
"pydata-sphinx-theme>=0.12",
"pytest-asyncio",
"pytest-asyncio>=0.20",
"pytest-cov",
"sphinx-autobuild",
"sphinx-copybutton",
Expand Down Expand Up @@ -91,7 +91,7 @@ addopts = """
# Next is something that needs to be fixed in PandABlocks-client asyncio.py's write_and_drain function
# which triggers a deprecation warning on Python 3.9+. See https://github.com/PandABlocks/PandABlocks-client/issues/47.
# a more recent version with a different C API. See https://github.com/mdavidsaver/p4p/issues/102.
# Remaining ignores are all related to the test DummyServer, both async and in_thread variants,
# Remaining ignores are all related to the test DummyServer, both async and in_thread variants,
# which appear to have issues cleanly shutting down and raise exceptions in their destructors.
# The issue seems like all we need is to add await asyncio.sleep(0) to allow asyncio to
# clean up its connections, but that doesn't seem to behave as expected inside pytest.
Expand All @@ -108,7 +108,10 @@ testpaths = "docs src tests"
asyncio_mode = "auto"

[tool.coverage.run]
concurrency = ["thread", "multiprocessing"]
data_file = "/tmp/pandablocks_ioc.coverage"
branch = true
omit = ["tests/*"]

[tool.coverage.paths]
# Tests are run from installed location, map back to the src directory
Expand All @@ -125,8 +128,8 @@ skipsdist=True
# Don't create a virtualenv for the command, requires tox-direct plugin
direct = True
passenv = *
allowlist_externals =
pytest
allowlist_externals =
pytest
pre-commit
mypy
sphinx-build
Expand Down
14 changes: 8 additions & 6 deletions src/pandablocks_ioc/_pvi.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def add_pvi_info(
"Q:group",
{
RecordName(f"{block}:PVI"): {
f"pvi.{field.replace(':', '_')}.{access}": {
f"pvi.{field.lower().replace(':', '_')}.{access}": {
"+channel": "NAME",
"+type": "plain",
}
Expand Down Expand Up @@ -175,22 +175,23 @@ def create_pvi_records(record_prefix: str):
for group, components in v.items():
children.append(Group(group.name, Grid(), components))

device = Device(block_name, children)
device = Device(block_name, children=children)
devices.append(device)

# Add PVI structure. Unfortunately we need something in the database
# that holds the PVI PV, and the QSRV records we have made so far aren't
# in the database, so have to make an extra record here just to hold the
# PVI PV name
pvi_record_name = block_name + ":PVI"
block_pvi = builder.stringIn(
pvi_record_name + "_PV", initial_value=RecordName(pvi_record_name)
block_pvi = builder.longStringIn(
pvi_record_name + "_PV",
initial_value=RecordName(pvi_record_name),
)
block_pvi.add_info(
"Q:group",
{
RecordName("PVI"): {
f"pvi.{block_name}.d": {
f"pvi.{block_name.lower()}.d": {
"+channel": "VAL",
"+type": "plain",
}
Expand All @@ -209,7 +210,8 @@ def create_pvi_records(record_prefix: str):
# Create top level Device, with references to all child Devices
device_refs = [DeviceRef(x, x) for x in pvi_records]

device = Device("TOP", device_refs)
# # TODO: What should the label be?
device = Device("TOP", children=device_refs)
devices.append(device)

# TODO: label widths need some tweaking - some are pretty long right now
Expand Down
92 changes: 65 additions & 27 deletions src/pandablocks_ioc/_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
import numpy as np
import numpy.typing as npt
from epicsdbbuilder import RecordName
from epicsdbbuilder.recordbase import PP
from pandablocks.asyncio import AsyncioClient
from pandablocks.commands import GetMultiline, Put
from pandablocks.responses import TableFieldDetails, TableFieldInfo
from pvi.device import ComboBox, SignalRW, TextWrite
from pvi.device import ComboBox, SignalRW, TableWrite, TextWrite
from softioc import alarm, builder, fields
from softioc.imports import db_put_field
from softioc.pythonSoftIoc import RecordWrapper
Expand Down Expand Up @@ -247,6 +248,7 @@ def __init__(
pva_table_name = RecordName(table_name)

# Make a labels field
block, field = table_name.split(":", maxsplit=1)
columns: RecordWrapper = builder.WaveformOut(
table_name + ":LABELS",
initial_value=np.array([k.encode() for k in field_info.fields]),
Expand All @@ -260,6 +262,21 @@ def __init__(
}
},
)
pv_rec = builder.longStringIn(
table_name + ":PV",
initial_value=pva_table_name,
)
pv_rec.add_info(
"Q:group",
{
RecordName(f"{block}:PVI"): {
f"pvi.{field.lower().replace(':', '_')}.rw": {
"+channel": "VAL",
"+type": "plain",
}
},
},
)

self.table_fields_records = OrderedDict(
{
Expand All @@ -271,11 +288,11 @@ def __init__(

# The PVI group to put all records into
pvi_group = PviGroup.PARAMETERS
# Pvi.add_pvi_info(
# table_name,
# pvi_group,
# SignalRW(table_name, table_name, TableWrite([])),
# )
Pvi.add_pvi_info(
table_name,
pvi_group,
SignalRW(table_name, table_name, TableWrite([])),
)

# The INDEX record's starting value
DEFAULT_INDEX = 0
Expand All @@ -291,9 +308,9 @@ def __init__(
value,
)

putorder_index = 0

for field_name, field_record_container in self.table_fields_records.items():
for i, (field_name, field_record_container) in enumerate(
self.table_fields_records.items()
):
field_details = field_record_container.field

full_name = table_name + ":" + field_name
Expand All @@ -313,32 +330,27 @@ def __init__(
length=field_info.max_length,
)

pva_info = {
f"value.{field_name.lower()}": {
"+type": "plain",
"+channel": "VAL",
"+putorder": putorder_index,
}
field_pva_info = {
"+type": "plain",
"+channel": "VAL",
"+putorder": i + 1,
"+trigger": "",
}

# Add metadata to the last column in the table
if putorder_index == len(self.table_fields_records) - 1:
pva_info.update({"": {"+type": "meta", "+channel": "VAL"}})
pva_info = {f"value.{field_name.lower()}": field_pva_info}

# For the last column in the table
if i == len(self.table_fields_records) - 1:
# Trigger a monitor update
field_pva_info["+trigger"] = "*"
# Add metadata
pva_info[""] = {"+type": "meta", "+channel": "VAL"}

field_record.add_info(
"Q:group",
{pva_table_name: pva_info},
)

putorder_index += 1

# TODO: TableWrite currently isn't implemented in PVI
# Pvi.add_pvi_info(
# full_name,
# pvi_group,
# SignalRW(full_name, full_name, TableWrite([TextWrite()])),
# )

field_record_container.record_info = RecordInfo(lambda x: x, None, False)

field_record_container.record_info.add_record(field_record)
Expand Down Expand Up @@ -432,6 +444,32 @@ def __init__(
self.mode_record_info.record = TableRecordWrapper(
self.mode_record_info.record, self
)
# PVA needs a record to start and finish processing, but these don't need
# putting on a screen
for action in (TableModeEnum.EDIT, TableModeEnum.SUBMIT):
action_record = builder.records.ao(
mode_record_name + ":" + action.name,
VAL=action.value,
MDEL=-1,
OUT=PP(mode_record),
)
# Edit mode done first, Submit mode done last
putorder = (
0 if action == TableModeEnum.EDIT else len(self.table_fields_records)
)
action_record.add_info(
"Q:group",
{
pva_table_name: {
f"_{action.name.lower()}": {
"+type": "proc",
"+channel": "PROC",
"+putorder": putorder,
"+trigger": "",
}
}
},
)

# Index record specifies which element the scalar records should access
index_record_name = EpicsName(table_name + ":INDEX")
Expand Down
14 changes: 13 additions & 1 deletion src/pandablocks_ioc/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,19 @@ def epics_to_panda_name(field_name: EpicsName) -> PandAName:
def device_and_record_to_panda_name(field_name: EpicsName) -> PandAName:
"""Convert an EPICS naming convention (including Device prefix) to PandA
convention."""
_, record_name = field_name.split(":", maxsplit=1)

if field_name.endswith(":LABEL"):
# Field is the label for the block, which is stored in the special
# *METADATA area

block_name = field_name.split(":")[-2]
if not block_name[-1].isdigit():
block_name += "1"

record_name = f"*METADATA.LABEL_{block_name}"
else:
_, record_name = field_name.split(":", maxsplit=1)

return epics_to_panda_name(EpicsName(record_name))


Expand Down
Loading

0 comments on commit 1f8caba

Please sign in to comment.