FTPMAN Protocol¶
Direct front-end access -- use with caution
This module communicates directly with front-end hardware controllers, bypassing all central services. Incorrect requests can disrupt data collection for other users, preempt active plots, and impact operations.
Prefer higher-level alternatives whenever possible:
- Continuous streaming up to 1440 Hz: Use
pacsys.subscribe()with a DPM backend -- DPM proxies FTP requests to front-ends on your behalf with proper resource management. - Snapshot plots: Consider ACL script if non-interactive collection is acceptable.
FTPMAN (Fast Time Plot Manager) is the ACNET protocol for high-frequency data acquisition from front-end controllers. It supports two modes:
- Continuous plots (FTP): real-time streaming at rates up to 1440 Hz
- Snapshot plots (SNP): triggered capture of up to 2048+ points at rates up to 20 MHz
All FTPMAN packets are ACNET request/reply payloads sent to the FTPMAN task on front-end nodes. All fields use little-endian byte order.
Using FTPClient¶
Query Capabilities¶
Every FTPMAN-capable channel has FTP and SNP classes which describe frontend capabilities.
from pacsys.acnet import AcnetConnectionTCP, FTPClient, FTPDevice
# You will need a special acnetd instance which allows FTPMAN over TCP (or use UDP)
# Clean up resources promptly/use context manager
with AcnetConnectionTCP() as conn:
# Always use the lowest priority (0, default)
ftp = FTPClient(conn)
node = conn.get_node("MUONFE")
dev = FTPDevice(di=27235, pi=12, ssdn=b"\x00\x00B\x00?!\x00\x00") # M:OUTTMP
codes = ftp.get_class_codes(node, dev)
print(f"FTP class: {codes.ftp}, Snapshot class: {codes.snap}")
# => FTP class: 16, Snapshot class: 13
Continuous FTP Streaming¶
from pacsys.acnet import AcnetConnectionTCP, FTPClient, FTPDevice
with AcnetConnectionTCP() as conn:
ftp = FTPClient(conn)
node = conn.get_node("MUONFE")
dev = FTPDevice(di=27235, pi=12, ssdn=b"\x00\x00B\x00?!\x00\x00") # M:OUTTMP
with ftp.start_continuous(node, [dev], rate_hz=1440) as stream:
for batch in stream.readings(timeout=1.0):
for di, points in batch.items():
for pt in points:
print(f"Device {di}: ts={pt.timestamp_us} us, val={pt.raw_value}")
# => Device 27235: ts=10000 us, val=42
# => Device 27235: ts=10700 us, val=45
# => ...
Immediate Snapshot¶
from pacsys.acnet import AcnetConnectionTCP, FTPClient, FTPDevice
with AcnetConnectionTCP() as conn:
ftp = FTPClient(conn)
node = conn.get_node("MUONFE")
dev = FTPDevice(di=27235, pi=12, ssdn=b"\x00\x00B\x00?!\x00\x00") # M:OUTTMP
# Default arm_source=2 (clock) with all-0xFF events = immediate arm
with ftp.start_snapshot(
node=node,
devices=[dev],
rate_hz=5000,
num_points=100,
snap_class_code=13, # enables auto skip_first_point
) as snap:
# Wait for collection (replaces manual sleep)
snap.wait(timeout=10.0)
# Retrieve data
points = snap.retrieve(device_index=0)
for pt in points[:5]:
print(f"ts={pt.timestamp_us} us, raw={pt.raw_value}")
# => ts=1000 us, raw=100
# => ts=1200 us, raw=105
# => ...
Clock-Event Armed Snapshot¶
from pacsys.acnet import AcnetConnectionTCP, FTPClient, FTPDevice
with AcnetConnectionTCP() as conn:
ftp = FTPClient(conn)
node = conn.get_node("MUONFE")
dev = FTPDevice(di=27235, pi=12, ssdn=b"\x00\x00B\x00?!\x00\x00") # M:OUTTMP
# Arm on TCLK event 0x02 -- each byte is a literal event number
arm_events = b"\x02" + b"\xff" * 7
with ftp.start_snapshot(
node=node,
devices=[dev],
rate_hz=5000,
num_points=100,
arm_events=arm_events,
snap_class_code=13,
) as snap:
snap.wait(timeout=15.0) # may wait up to one supercycle (~5s)
points = snap.retrieve(device_index=0)
print(f"Got {len(points)} points")
# => Got 99 points
Restart (Re-arm) Cycle¶
from pacsys.acnet import AcnetConnectionTCP, FTPClient, FTPDevice
with AcnetConnectionTCP() as conn:
ftp = FTPClient(conn)
node = conn.get_node("MUONFE")
dev = FTPDevice(di=27235, pi=12, ssdn=b"\x00\x00B\x00?!\x00\x00") # M:OUTTMP
with ftp.start_snapshot(
node=node,
devices=[dev],
rate_hz=5000,
num_points=100,
snap_class_code=13,
) as snap:
for cycle in range(3):
snap.wait(timeout=10.0)
points = snap.retrieve(device_index=0)
print(f"Cycle {cycle}: {len(points)} points")
# => Cycle 0: 99 points
# => Cycle 1: 99 points
# => Cycle 2: 99 points
snap.restart() # re-arm for next capture - avoids repeated setup
Sequential Multi-Chunk Retrieval¶
For large captures that exceed retrieval_max (512 for most classes):
from pacsys.acnet import AcnetConnectionTCP, FTPClient, FTPDevice
with AcnetConnectionTCP() as conn:
ftp = FTPClient(conn)
node = conn.get_node("MUONFE")
dev = FTPDevice(di=27235, pi=12, ssdn=b"\x00\x00B\x00?!\x00\x00") # M:OUTTMP
with ftp.start_snapshot(
node=node,
devices=[dev],
rate_hz=5000,
num_points=2048,
snap_class_code=13,
) as snap:
snap.wait(timeout=10.0)
# Retrieve in 512-point chunks using sequential access.
# First chunk: skip metadata point. Subsequent: don't skip.
all_points = []
first = True
while True:
points = snap.retrieve(
device_index=0,
num_points=512,
point_number=-1, # sequential access
skip_first_point=first,
)
first = False
if not points:
break
all_points.extend(points)
print(f"Total: {len(all_points)} points")
# => Total: 2047 points (2048 minus 1 skipped metadata point)
Class Code Lookup¶
from pacsys.acnet.ftp import get_ftp_class_info, get_snap_class_info
ftp_info = get_ftp_class_info(16) # C290 MADC
snap_info = get_snap_class_info(13) # C290 MADC snapshot
print(f"FTP max rate: {ftp_info.max_rate} Hz")
# => FTP max rate: 1440 Hz
print(f"Snap max rate: {snap_info.max_rate} Hz, "
f"max points: {snap_info.max_points}, "
f"has_timestamps: {snap_info.has_timestamps}")
# => Snap max rate: 90000 Hz, max points: 2048, has_timestamps: True
Continuous Plot Flow¶
sequenceDiagram
participant C as Client
participant FE as Front-End (FTPMAN)
C->>FE: Typecode 1 (class info query)
FE-->>C: Class codes per device
C->>FE: Typecode 6 (continuous setup, multiple-reply)
FE-->>C: Setup reply (per-device status)
loop Every return_period (2-7 Hz)
FE-->>C: Data reply (timestamped points)
end
C->>FE: ACNET cancel (stop)
Snapshot Plot Flow¶
sequenceDiagram
participant C as Client
participant FE as Front-End (FTPMAN)
C->>FE: Typecode 1 (class info query)
FE-->>C: Class codes per device
C->>FE: Typecode 7 (snapshot setup, multiple-reply)
FE-->>C: Setup reply (parameters + per-device status)
loop Until collection complete
FE-->>C: Status reply (WAIT_EVENT → COLLECTING → done)
end
loop One request per device, chunked if needed
C->>FE: Typecode 8 (retrieve, single-reply)
FE-->>C: Data reply (points for one device)
end
opt Re-arm for another capture
C->>FE: Typecode 5 subtype=1 (restart)
FE-->>C: Status reply
loop Until collection complete
FE-->>C: Status reply
end
loop Retrieve again
C->>FE: Typecode 8 (retrieve)
FE-->>C: Data reply
end
end
C->>FE: ACNET cancel (stop)
Typecodes¶
| Typecode | Operation | Reply Mode | Description |
|---|---|---|---|
| 1 | Class info query | Single | Query FTP/snapshot capabilities per device |
| 5 | Snapshot control | Single | Restart (re-arm) or reset retrieval pointers |
| 6 | Continuous setup | Multiple | Start streaming data at specified rate |
| 7 | Snapshot setup | Multiple | Arm snapshot capture with trigger parameters |
| 8 | Snapshot retrieve | Single | Retrieve captured data (one device per request) |
Class Code Query (Typecode 1)¶
Before starting any plot, clients query the front-end for each device's capabilities.
Request¶
[2B: typecode = 1]
[2B: num_devices]
Per device (12B):
[4B: DIPI] Property-Device Index Pair
[8B: SSDN] Sub-System Device Number
Reply¶
[2B: error (signed)] Overall status
Per device (6B):
[2B: error (signed)] Per-device status
[2B: FTP class code] Continuous plot class (0 = unsupported)
[2B: SNP class code] Snapshot class (0 = unsupported)
FTP Class Codes (Continuous)¶
Codes 1-10 are defunct. Only 11+ use the current typecode 6 protocol.
| Code | Hardware | Max Rate |
|---|---|---|
| 11 | C190 MADC channel | 720 Hz |
| 12 | Internet Rack Monitor | 1000 Hz |
| 13 | MRRF MAC MADC channel | 100 Hz |
| 14 | Booster MAC MADC channel | 15 Hz |
| 15 | 15 Hz (Linac, D/A's, etc.) | 15 Hz |
| 16 | C290 MADC channel | 1440 Hz |
| 17 | 15 Hz from data pool | 15 Hz |
| 18 | 60 Hz internal | 60 Hz |
| 19 | 68K (MECAR) | 1440 Hz |
| 20 | Tev Collimators | 240 Hz |
| 21 | IRM 1 KHz Digitizer | 1000 Hz |
| 22 | DAE 1 Hz | 1 Hz |
| 23 | DAE 15 Hz | 15 Hz |
Snapshot Class Codes¶
Codes 1-9 are defunct. Only 11+ use the current typecode 7 protocol.
| Code | Hardware | Max Rate | Max Points | Timestamps | Triggers |
|---|---|---|---|---|---|
| 11 | C190 MADC channel | 66 KHz | 2048 | Yes | No |
| 12 | 1440 Hz internal | 1440 Hz | 2048 | Yes | No |
| 13 | C290 MADC channel | 90 KHz | 2048 | Yes | No |
| 14 | 15 Hz internal | 15 Hz | 2048 | Yes | No |
| 15 | 60 Hz internal | 60 Hz | 2048 | Yes | No |
| 16 | Quick Digitizer (Linac) | 10 MHz | 4096 | No | No |
| 17 | 720 Hz internal | 720 Hz | 2048 | Yes | No |
| 18 | New FRIG circ buffer | 1 KHz | 16384 | Yes | Yes |
| 19 | Swift Digitizer | 800 KHz | 4096 | No | No |
| 20 | IRM 20 MHz Quick Digitizer | 20 MHz | 4096 | No | No |
| 21 | IRM 1 KHz Digitizer | 1 KHz | 4096 | No | No |
| 22 | DAE 1 Hz | 1 Hz | 4096 | Yes | Yes |
| 23 | DAE 15 Hz | 15 Hz | 4096 | Yes | Yes |
| 24 | IRM 12.5 KHz Digitizer | 12.5 KHz | 4096 | No | No |
| 25 | IRM 10 KHz Digitizer | 10 KHz | 4096 | No | No |
| 26 | IRM 10 MHz Digitizer | 10 MHz | 4096 | No | No |
| 28 | New Booster BLM | 12.5 KHz | 4096 | No | No |
The Timestamps column determines whether snapshot data includes per-point timestamps or just raw values. Clients must know this from the class code before retrieving data.
Continuous Plot (Typecode 6)¶
Setup Request¶
[2B: typecode = 6]
[4B: task_name] RAD50-encoded unique name (auto-generated)
[2B: num_devices]
[2B: return_period] 15 Hz ticks between replies (1-7)
[2B: msg_size_words] Max reply buffer size in 16-bit words
[2B: ref_word] Reserved (0)
[2B: start_time] Reserved (0)
[2B: stop_time] Reserved (0)
[2B: priority] 0=user, 1=other CR, 2=main CR, 3=SDA
[2B: current_time_15hz] For FEs without 0x02 event hardware (0)
[10B: zeros] Reserved
Per device (22B):
[4B: DIPI]
[4B: offset] Byte offset into device data
[8B: SSDN]
[2B: sample_period] In 10 us units
[4B: zeros] Reserved
Buffer size calculation: msg_size = min(1.5 * (4 + 3*N + dataWords * rate * period/15), 4160) where 4160 = MAX_ACNET_MSG_SIZE / 2.
Behavior notes:
- Sent as a multiple-reply ACNET request. Cancel to stop.
- If ANY device cannot be accommodated, the entire request is rejected.
- Each plotting task can have only one active plot. A new request auto-cancels the previous one.
- The sample period (10 us units) is the only way to specify collection rate. Event-based sampling is not supported (use RETDAT for that).
- Data length (2 or 4 bytes) is not specified in the request; the FE uses the default from the device database.
First Reply (Setup Acknowledgement)¶
If error < 0, the request failed and this is the last reply. Positive per-device status codes are informational (see FTP Status Codes).
Data Replies¶
[2B: error (signed)]
[2B: reply_type = 2]
[4B: reserved]
Per device (6B):
[2B: error (signed)] Per-device status (negative = skip this device's data)
[2B: ptr_to_data] Byte offset from start of reply to first data point
[2B: num_points] Number of points returned
Variable data per device:
Per point:
[2B: timestamp] 100 us resolution, relative to TCLK event 0x02
[2B or 4B: value] Raw data value (2 or 4 bytes per device's data_length)
Error handling: Only negative values in the header error field indicate errors. Positive values (including FTP_COLLECTING) are informational. Per-device errors use != 0 (any non-zero skips that device's data for this reply).
Timestamps: Unsigned 16-bit values with 100 microsecond resolution, reset on each TCLK event 0x02 (which occurs every 5 seconds). Multiply by 100 to convert to microseconds.
Snapshot Plot (Typecodes 7, 8, 5)¶
Snapshot plots have three phases: setup (arm), retrieval, and optional restart/reset.
Setup Request (Typecode 7)¶
Total size: 68 + 20*N bytes.
[2B: typecode = 7]
[4B: task_name] RAD50-encoded unique name (auto-generated)
[2B: num_devices]
[2B: arm_trigger_word] See Arm and Trigger Selection Word below
[2B: priority] Same as continuous (0-3)
[4B: rate_hz] Data sample rate in Hz
[4B: arm_delay] Microseconds (post-trigger) or sample count (pre-trigger)
[8B: arm_clock_events] Literal event numbers (NOT a bitmask), 0xFF = unused
[4B: sample_trigger_events] Literal event numbers (NOT a bitmask), 0xFF = unused
[4B: num_points] Points to collect per device
[4B: arm_dipi] Arm device DIPI (if arm source = device)
[4B: arm_offset] Arm device byte offset
[8B: arm_ssdn] Arm device SSDN
[4B: arm_mask] Arm condition mask
[4B: arm_value] Arm condition value
[8B: zeros] Reserved
Per device (20B):
[4B: DIPI]
[4B: offset]
[8B: SSDN]
[4B: zeros] Reserved
Behavior notes:
- Sent as a multiple-reply ACNET request. Cancel to abort.
- Unlike continuous plots, the request succeeds if ANY device can be accommodated (partial success).
- The FE may adjust parameters (rate, num_points, etc.) to match hardware capabilities. Actual values are returned in the setup reply.
- The arm condition (for device-triggered arm):
(device_value & mask) == value.
Arm and Trigger Selection Word¶
The Java DPM implementation uses a slightly different bit layout from the original 1998 protocol spec, with a "new protocol" flag at bit 7:
| Field | Bits | Values |
|---|---|---|
| AS (Arm Source) | 1:0 | 0=device, 2=clock events, 3=external (AM specifies which) |
| AM (Arm Modifier) | 3:2 | 0-3, only meaningful when AS=3 |
| PM (Plot Mode) | 6:5 | 2=post-trigger, 3=pre-trigger (0 and 1 are invalid) |
| NP (New Protocol) | 7 | Always 1 (indicates new typecode 7 protocol) |
| TS (Trigger Source) | 9:8 | 0=periodic (use rate_hz), 2=clock events, 3=external (TM specifies which) |
| TM (Trigger Modifier) | 11:10 | 0-3, only meaningful when TS=3 |
AS=1 (ARM_IMMEDIATELY) is not used
The protocol defines AS=1 as "arm immediately", but the Java SnapShotPool never sends it on the wire. Even for immediate arming, it sends AS=2 (clock events) with all-0xFF arm events and arm_delay=0. Some front-ends (ecbpm) reject AS=1. The pacsys implementation follows this Java convention.
Plot modes:
- Post-trigger (PM=2): After the arm condition, wait
arm_delaymicroseconds, then collectnum_pointsdata points. - Pre-trigger (PM=3): Begin collecting immediately. After the arm condition, collect
arm_delaymore samples, then stop.
Setup Reply¶
First reply after sending the setup request:
[2B: error (signed)] FTP-level status (negative = fatal error)
[2B: arm_trigger_word] Actual arm/trigger word chosen by FE
[4B: rate_hz] Actual sample rate
[4B: arm_delay] Actual arm delay
[8B: arm_events] Actual arm clock events
[4B: num_points] Actual number of points
Per device (18B):
[2B: error (signed)] Per-device status
[4B: ref_point] Reference point number (pre-trigger only)
[4B: arm_sec] Arm time, seconds since 1970-01-01
[4B: arm_nsec] Arm time, nanoseconds within second
[4B: reserved]
Short error replies: If the front-end rejects the request outright, it may return only the 2-byte error field with no further data. Always check the error before attempting to parse the full reply.
Per-device status: Positive values are informational and expected:
| Status | Meaning |
|---|---|
FTP_PEND [15 1] |
Snapshot setup accepted, pending |
FTP_WAIT_EVENT [15 2] |
Armed, waiting for arm event |
FTP_WAIT_DELAY [15 3] |
Armed, waiting for delay |
FTP_COLLECTING [15 4] |
Data collection in progress |
Subsequent multiple-reply messages carry updated status as collection progresses.
Retrieve Data (Typecode 8)¶
Sent as a single-reply request to retrieve captured data for one device at a time.
[2B: typecode = 8]
[4B: task_name] RAD50-encoded (must match setup)
[2B: item_number] 1-based index into the setup device list
[2B: num_points] Number of points to retrieve
[4B: point_number] Starting point (0-based) or 0xFFFFFFFF for sequential access
Total: 14 bytes.
Retrieve Reply¶
[2B: error (signed)]
[2B: num_points_returned]
Per point (variable):
[2B: timestamp] 100 us resolution (only if class has_timestamps)
[2B or 4B: value] Raw data value
Timestamps: Whether timestamps are included depends on the snapshot class code. Classes like Quick Digitizer (code 16) and Swift Digitizer (code 19) return raw values only. Check SnapClassInfo.has_timestamps for the device's class.
Post-trigger retrieval: Data can be retrieved while collection is still in progress. Pre-trigger requires waiting until all data is collected.
Restart / Reset (Typecode 5)¶
[2B: typecode = 5]
[4B: task_name] RAD50-encoded (must match setup)
[2B: subtype] 1 = restart (re-arm), 2 = reset retrieval pointers
Total: 8 bytes.
Restart (subtype 1): Re-arms the snapshot with the same parameters. The front-end begins waiting for the arm condition again.
Reset (subtype 2): Resets the data retrieval pointers so subsequent typecode 8 requests return data from the beginning again.
Reply: [2B: error (signed)]
FTP Status Codes¶
FTP uses ACNET facility 15. Status codes follow the standard [facility error_number] convention: negative = error, zero = success, positive = informational.
Informational (positive)¶
| Code | Constant | Error # | Description |
|---|---|---|---|
| [15 4] | FTP_COLLECTING |
+4 | Snapshot data collection in progress |
| [15 3] | FTP_WAIT_DELAY |
+3 | Snapshot armed, waiting for time delay |
| [15 2] | FTP_WAIT_EVENT |
+2 | Snapshot armed, waiting for arm event |
| [15 1] | FTP_PEND |
+1 | Snapshot pending (setup accepted) |
Errors (negative)¶
| Code | Constant | Error # | Description |
|---|---|---|---|
| [15 -1] | FTP_INVTYP |
-1 | Invalid request typecode (software bug) |
| [15 -2] | FTP_INVSSDN |
-2 | Invalid SSDN from database |
| [15 -5] | FTP_FE_OUTOFMEM |
-5 | Front-end out of memory |
| [15 -6] | FTP_NOCHAN |
-6 | No available MADC plot channels |
| [15 -7] | FTP_NO_DECODER |
-7 | No available MADC clock decoders |
| [15 -8] | FTP_FE_PLOTLIM |
-8 | Front-end plot limit exceeded |
| [15 -9] | FTP_INVNUMDEV |
-9 | Invalid number of devices in request |
| [15 -10] | FTP_ENDOFDATA |
-10 | End of data |
| [15 -11] | FTP_FE_PLOTLEN |
-11 | Buffer length computation error |
| [15 -12] | FTP_INVREQLEN |
-12 | Invalid request length |
| [15 -13] | FTP_NO_DATA |
-13 | No data from MADC (transient or hardware) |
| [15 -14] | FTP_INVREQ |
-14 | Retrieval doesn't match active setup |
| [15 -15] | FTP_BADEV |
-15 | Wrong set of clock events |
| [15 -16] | FTP_BUMPED |
-16 | Bumped by higher priority plot |
| [15 -17] | FTP_REROUTE |
-17 | Internal front-end reroute error |
| [15 -19] | FTP_UNSFREQ |
-19 | Unsupported frequency |
| [15 -20] | FTP_BIGDLY |
-20 | Arm delay too long |
| [15 -21] | FTP_UNSDEV |
-21 | Unsupported device type |
| [15 -22] | FTP_SOFTWARE |
-22 | Internal front-end software error |
| [15 -23] | FTP_NOTRDY |
-23 | Snapshot data not yet ready |
| [15 -24] | FTP_ARCNET |
-24 | ARCNET communication error |
| [15 -25] | FTP_BADARM |
-25 | Bad arm value, can't decode arm word |
| [15 -26] | FTP_INVFREQ_FOR_HARDWARE |
-26 | Frequency unsupported by hardware |
| [15 -27] | FTP_BAD_PLOT_MODE |
-27 | Bad plot mode in arm/trigger word |
| [15 -28] | FTP_NO_SUCH_DEVICE |
-28 | Device not found for retrieval |
| [15 -29] | FTP_DEVICE_IN_USE |
-29 | Device already has active retrieval |
| [15 -30] | FTP_FREQ_TOO_HIGH |
-30 | Frequency exceeds front-end capability |
| [15 -31] | FTP_NO_SETUP |
-31 | No matching setup for retrieval/restart |
| [15 -32] | FTP_UNSUPPORTED_PROP |
-32 | Unsupported property |
| [15 -33] | FTP_INVALID_CHANNEL |
-33 | Channel doesn't exist on device |
| [15 -34] | FTP_NO_FIFO |
-34 | Missing FIFO board |
| [15 -35] | FTP_BAD_DATA_LENGTH |
-35 | Invalid data length (expected 2 or 4) |
| [15 -36] | FTP_BUFFER_OVERFLOW |
-36 | Front-end buffer overflow |
| [15 -37] | FTP_NO_EVENT_SUPPORT |
-37 | Event-triggered sampling unsupported |
| [15 -38] | FTP_TRIGGER_ERROR |
-38 | Internal trigger definition error |
| [15 -39] | FTP_INV_CLASS_DEF |
-39 | Invalid class definition |
| [15 -40] | FTP_NO_RANDOM_ACCESS |
-40 | Random access not supported |
| [15 -41] | FTP_INVALID_OFFSET |
-41 | Non-zero data offset unsupported |
| [15 -42] | FTP_NO_SNAPSHOT |
-42 | Device doesn't support snapshots |
| [15 -43] | FTP_EVENT_UNAVAILABLE |
-43 | Clock event not available on front-end |
| [15 -44] | FTP_NO_FTPMAN_INIT |
-44 | FTPMAN not initialized (send class query first) |
| [15 -100] | FTP_BADTIMES |
-100 | UCD module timestamp error |
| [15 -101] | FTP_BADRESETS |
-101 | Device timestamp reset error |
| [15 -102] | FTP_BADARG |
-102 | Invalid argument |
| [15 -103] | FTP_BADRPY |
-103 | Invalid reply from front-end |
All constants are available from pacsys.acnet.errors.
Priority¶
Plots compete for front-end resources. Higher priority plots can preempt lower priority ones. FTP and snapshot share the same resource pool, so a high-priority snapshot can preempt a continuous plot.
| Priority | Context |
|---|---|
| 0 | User (default) |
| 1 | Other control room |
| 2 | Main control room |
| 3 | SDA (Save/Data/Analyze) |
Implementation Notes¶
Differences from the 1998 Protocol Spec¶
The Java codebase is the authoritative implementation. Key differences from the original FTPMAN spec:
- Arm/trigger word bit layout: Java implementation adds a "new protocol" flag at bit 7.
task_namefield: Each setup gets a unique RAD50-encoded name (e.g. SNP001, SNP002) so the FE can match retrieval/restart requests back to the correct setup. TheFTPClientgenerates these automatically.- Error signedness: All error fields are signed 16-bit integers. Only negative values indicate errors; positive values are informational status codes (e.g.,
FTP_COLLECTING = +4). - ARM_IMMEDIATELY not used: Java SnapShotPool never puts AS=1 on the wire. For immediate arming it uses AS=2 (clock events) with all-0xFF arm events. Some FEs (ecbpm) reject AS=1.
arm_clock_eventsencoding: Each byte is a literal TCLK event number (0x00–0xFD), NOT a bitmask. 0xFE and 0xFF mean "unused slot". For event 0x02:[0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF].
Error Handling Pattern¶
FTPMAN replies have two levels of error checking:
- ACNET packet status (
reply.status): Checked first. If negative, the entire reply is an error and there is no payload to parse. - FTP-level error (first 2 bytes of payload): The FE-level status. When the front-end rejects a request, this may be the only data returned (just 2 bytes).
Always check error fields before attempting to parse reply data.
acnetd Task Restrictions¶
Most acnetd instances (including all clx ones) restrict TCP client access to certain tasks (including FTPMAN). If you get an AcnetRequestRejectedError with the message "task is on the TCP reject list", you must either run your own acnetd instance on a node you have access to, or login to one of clx nodes and use AcnetConnectionUDP.
DIPI Encoding¶
The Property-Device Index Pair packs the property index and device index into a single 32-bit value:
SSDN¶
The Sub-System Device Number is an 8-byte opaque identifier from the device database. It encodes hardware-specific addressing (crate, slot, channel, etc.) and must be passed through unchanged. You can use D80 or ACL to find it.