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

Make pv names consistent with web gui names #26

Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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?
evalott100 marked this conversation as resolved.
Show resolved Hide resolved
device = Device("TOP", children=device_refs)
devices.append(device)

# TODO: label widths need some tweaking - some are pretty long right now
Expand Down
84 changes: 61 additions & 23 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",
}
},
},
)
evalott100 marked this conversation as resolved.
Show resolved Hide resolved

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,7 +308,7 @@ def __init__(
value,
)

putorder_index = 0
putorder_index = 1
evalott100 marked this conversation as resolved.
Show resolved Hide resolved

for field_name, field_record_container in self.table_fields_records.items():
field_details = field_record_container.field
Expand All @@ -313,17 +330,21 @@ 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": putorder_index,
"+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 putorder_index == len(self.table_fields_records):
# Trigger a monitor update
field_pva_info["+trigger"] = "*"
# Add metadata
pva_info[""] = {"+type": "meta", "+channel": "VAL"}

field_record.add_info(
"Q:group",
Expand All @@ -332,13 +353,6 @@ def __init__(

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 +446,30 @@ 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 putorder_index
evalott100 marked this conversation as resolved.
Show resolved Hide resolved
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
13 changes: 12 additions & 1 deletion src/pandablocks_ioc/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,18 @@ 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"):
# Device is a metadata_label field
evalott100 marked this conversation as resolved.
Show resolved Hide resolved

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
Loading