DiamondLightSource / DiamondLightSource/fastcs

Tango device TRL naming for hierarchical FastCS controllers — two options for community input

Open
#381 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
6
Forks
8
Avg merge
2d 12h
Merged PRs (30d)
3

Description

# Tango device TRL naming for hierarchical FastCS controllers — two options for community input

We are adding Tango support to [FastCS](https://github.com/DiamondLightSource/fastcs),
a Python framework that auto-generates control-system interfaces from a class
hierarchy describing an instrument. We need community input on how to map that
hierarchy to Tango TRLs.

---

## Context: the PandA example

[PandA](https://pandablocks.readthedocs.io/) is a motion-sequencing controller
used at several UK/EU synchrotrons. A site may run multiple PandA boards, each
exposing a hierarchy of typed functional blocks, some with multiple instances
(vectors). In FastCS this maps to:

```
Panda ← top-level controller (one per physical board)
├── SeqVector
│ ├── Seq[1] ← has attributes: enable, prescale, table, …
│ └── Seq[2]
├── PulseVector
│ ├── Pulse[1]
│ └── Pulse[2]
└── Pcap ← singular block; attributes: enable, arm, …
```

Each node should become **one Tango device** exposing only its own attributes.
The question is how to assign TRLs, given that a deployment has – say – two
PandA boards on beamline BL04I. The EPICS PV convention at Diamond for the two
sequencer blocks on PandA board 2 is `BL04I-EA-PANDA-02:SEQ:1` and
`BL04I-EA-PANDA-02:SEQ:2`.

---

## Naming convention baseline (from community examples)

The Tango community norm we have observed (ESRF, Soleil, MAX IV, ALBA, DESY, SKA):

| TRL segment | Meaning | Style |
|---|---|---|
| **domain** | site / facility / beamline | uppercase or lowercase depending on site |
| **family** | hyphen-joined device-type hierarchy | lowercase-hyphen |
| **member** | dot-joined instance indices | purely numeric |

SKA reference (confirmed by SKA developer):
```
mid-cbf/mcs-fsp/01
mid-cbf/mcs-fsp-corr-subarray/01.03 ← FSP 01, subarray 03
```

Family = full type path; member = all instance indices in hierarchy order. This
gives clean wildcards: `BL04I/panda-seq/*` = every SEQ block on the beamline.

The challenge for PandA is that the board number (e.g. `2` for `PANDA-02`) is
**not** a `ControllerVector` index inside the FastCS hierarchy — it is the
identity of the top-level controller. There is no natural place in the path for
it. Two options follow.

---

## Option A — Board number encoded in the controller id, split at the transport

The user names each top-level controller `-`. FastCS validates that
ids used with the Tango transport must end in `-n` where `n` is purely numeric
(e.g. `panda-2` is valid; `panda-2-ext` is not). The transport strips the
trailing `-n`, using the string part for the family and the numeric part as the
first member index.

```yaml
# fastcs.yaml (two PandA boards on BL04I)
controllers:
- id: panda-1
type: pandablocks.Panda
port: 8888
- id: panda-2
type: pandablocks.Panda
port: 8889

transport:
- tango:
domain: BL04I
```

**TRL derivation**: for a path like `["panda-2", "seq", 1]`, split the id into
string part `panda` and numeric part `2`; collect all numeric parts
(id suffix + ControllerVector indices) into the member, all string parts into
the family.

| Device | FastCS path | TRL |
|---|---|---|
| PandA 2 — top-level | `["panda-2"]` | `BL04I/panda/2` |
| PandA 2 — Pcap | `["panda-2", "pcap"]` | `BL04I/panda-pcap/2` |
| PandA 2 — Seq[1] | `["panda-2", "seq", 1]` | `BL04I/panda-seq/2.1` |
| PandA 2 — Seq[2] | `["panda-2", "seq", 2]` | `BL04I/panda-seq/2.2` |
| PandA 1 — Seq[1] | `["panda-1", "seq", 1]` | `BL04I/panda-seq/1.1` |

**Wildcard examples**:
- All Seq blocks on BL04I: `BL04I/panda-seq/*` ✓
- All Seq blocks on PandA 2: `BL04I/panda-seq/2.*` ✓
- All devices of PandA 2: no single wildcard (different family per block type)

**Problem**: a single board's devices span multiple families (`panda`,
`panda-pcap`, `panda-seq`, …), so there is no wildcard to select all devices
belonging to one physical board.

---

## Option B — Full base TRL as the controller id

The controller id is itself a valid Tango TRL (`D/F/M`). FastCS derives
sub-controller TRLs by appending the relative sub-path (all segments,
hyphen-joined) to the member segment. FastCS validates every resulting TRL
before registering.

```yaml
# fastcs.yaml (two PandA boards on BL04I)
controllers:
- id: BL04I/panda/1
type: pandablocks.Panda
port: 8888
- id: BL04I/panda/2
type: pandablocks.Panda
port: 8889

transport:
- tango: {}
```

**TRL derivation**: for id `D/F/M` and relative path `[s1, s2, …]`,
the sub-controller TRL is `D/F/M-s1-s2-…`.

| Device | FastCS path | TRL |
|---|---|---|
| PandA 2 — top-level | `["BL04I/panda/2"]` | `BL04I/panda/2` |
| PandA 2 — Pcap | `["BL04I/panda/2", "pcap"]` | `BL04I/panda/2-pcap` |
| PandA 2 — Seq[1] | `["BL04I/panda/2", "seq", 1]` | `BL04I/panda/2-seq-1` |
| PandA 2 — Seq[2] | `["BL04I/panda/2", "seq", 2]` | `BL04I/panda/2-seq-2` |
| PandA 1 — Seq[1] | `["BL04I/panda/1", "seq", 1]` | `BL04I/panda/1-seq-1` |

**Wildcard examples**:
- All devices of PandA 2: `BL04I/panda/2*` ✓
- All PandA devices on BL04I: `BL04I/panda/*` ✓
- All Seq blocks on BL04I: `BL04I/panda/*-seq-*`

**Problem**: the member field mixes type names with instance indices
(`2-seq-1`), departing from the convention that member = purely numeric indices.
Tools that parse the member as structured numeric data would need to handle this.

---

## Comparison

| | Option A | Option B |
|---|---|---|
| Family | Clean type hierarchy (`panda-seq`) | Clean type hierarchy (`panda`) |
| Member | Purely numeric (`2.1`) ✓ | Mixed type + indices (`2-seq-1`) |
| SKA `family/member` convention | ✓ matches | ✗ non-numeric member |
| Wildcard: all Seq blocks | `BL04I/panda-seq/*` ✓ | `BL04I/panda/*-seq-*` |
| Wildcard: all devices of one board | No single wildcard | `BL04I/panda/2*` ✓ |
| Wildcard: all PandA devices | `BL04I/panda*/` (catches other families) | `BL04I/panda/*` ✓ |
| Config burden | `domain` only | Per-controller base TRL |
| Id constraint | Must end in `-n` | No constraint |

---

## Question for the Tango community

**Which option is preferable in practice — and does the choice matter for real
tooling at your facility?**

1. Does a non-numeric member (`2-seq-1`, Option B) break any archiving, alarm,
or subscription tooling you use?
2. Is the inability to wildcard across one physical board's devices (Option A) a
practical problem, or do users typically subscribe by device type rather than
by physical unit?
3. Is there a third pattern we have not considered?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.