import math
import time
import spvirit
builder = spvirit.ServerBuilder()
builder.ai("SIM:TEMPERATURE", 22.5)
builder.ai("SIM:SINE", 0.0)
builder.ao("SIM:SETPOINT", 25.0)
builder.bi("SIM:INTERLOCK", False) builder.bo("SIM:ENABLE", True)
builder.string_in("SIM:STATUS", "IDLE")
builder.string_out("SIM:COMMAND", "")
builder.waveform("SIM:WAVEFORM", [0.0] * 64)
builder.aai("SIM:HISTOGRAM", [0] * 32)
builder.aao("SIM:SETPOINTS_ARRAY", [1.0, 2.0, 3.0, 4.0, 5.0])
builder.sub_array("SIM:SUBARRAY", list(range(100)), indx=10, nelm=20)
builder.nt_table("SIM:TABLE", {
"name": ["Alice", "Bob", "Charlie"],
"score": [95.0, 87.5, 92.0],
"rank": [1, 2, 3],
})
width, height = 16, 16
pixels = [float(i % 256) for i in range(width * height)]
builder.nt_ndarray("SIM:IMAGE", pixels, [(width, width), (height, height)])
builder.mbbi("SIM:STATE", ["Idle", "Running", "Paused", "Error"], 0) builder.mbbo("SIM:MODE", ["Standby", "Acquire", "Calibrate"], 0)
builder.generic("SIM:METADATA", "demo:custom/Meta:1.0", {
"author": "spvirit",
"version": 1,
"rating": 9.5,
})
builder.ao("SIM:PRESSURE", 0.0) builder.waveform("SIM:SPECTRUM", [0.0] * 128)
def on_setpoint(pv_name, value):
print(f"[on_put] {pv_name} = {value}")
builder.on_put("SIM:SETPOINT", on_setpoint)
def on_command(pv_name, value):
print(f"[command] {pv_name} = {value!r}")
builder.on_put("SIM:COMMAND", on_command)
def on_enable(pv_name, value):
print(f"[enable] {pv_name} = {value}")
builder.on_put("SIM:ENABLE", on_enable)
def on_state(pv_name, value):
states = ["Idle", "Running", "Paused", "Error"]
idx = int(value) if isinstance(value, (int, float)) else 0
label = states[idx] if 0 <= idx < len(states) else "?"
print(f"[state] {pv_name} = {idx} ({label})")
builder.on_put("SIM:STATE", on_state)
t0 = time.time()
def sine_scan(pv_name):
elapsed = time.time() - t0
return 22.5 + 5.0 * math.sin(elapsed)
builder.scan("SIM:SINE", 0.5, sine_scan)
def temperature_scan(pv_name):
import random
return 22.5 + random.uniform(-1.0, 1.0)
builder.scan("SIM:TEMPERATURE", 2.0, temperature_scan)
builder.port(5075)
builder.udp_port(5076)
builder.beacon_period(15)
builder.compute_alarms(True)
server = builder.build()
store = server.start_background()
print("Server running on port 5075 — press Ctrl+C to stop")
print(f"Serving {len(store.pv_names())} PVs: {store.pv_names()}")
pressure_nt = spvirit.NtScalar(
101.325,
units="kPa",
display_low=80.0,
display_high=120.0,
display_description="Vacuum chamber pressure",
display_precision=3,
control_low=90.0,
control_high=110.0,
control_min_step=0.001,
)
store.put_nt("SIM:PRESSURE", pressure_nt)
spectrum_data = [math.sin(2 * math.pi * i / 128) * 100.0 for i in range(128)]
spectrum_nt = spvirit.NtScalarArray(spectrum_data)
store.put_nt("SIM:SPECTRUM", spectrum_nt)
try:
tick = 0
while True:
elapsed = time.time() - t0
wf = [math.sin(2 * math.pi * i / 64 + elapsed) for i in range(64)]
store.set_array_value("SIM:WAVEFORM", wf)
import random
hist = [random.randint(0, 100) for _ in range(32)]
store.set_array_value("SIM:HISTOGRAM", hist)
STATE_CHOICES = ["Idle", "Running", "Paused", "Error"]
state_idx = (tick // 4) % len(STATE_CHOICES)
store.set_value("SIM:STATE", state_idx)
pressure = 101.325 + 2.0 * math.sin(elapsed * 0.3) + random.gauss(0, 0.05)
alarm_cycle = tick % 20
if alarm_cycle < 10:
sev, status, msg = 0, 0, ""
desc = f"Vacuum chamber pressure — stable (t={elapsed:.1f}s)"
elif alarm_cycle < 15:
sev, status, msg = 1, 3, f"Pressure drifting high: {pressure:.3f} kPa"
desc = f"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"
pressure += 5.0 else:
sev, status, msg = 2, 3, f"Pressure CRITICAL: {pressure + 10:.3f} kPa"
desc = f"CRITICAL: chamber over-pressure! (t={elapsed:.1f}s)"
pressure += 10.0
p_nt = spvirit.NtScalar(
pressure,
units="kPa",
display_low=80.0,
display_high=120.0,
display_description=desc,
display_precision=3,
control_low=90.0,
control_high=110.0,
control_min_step=0.001,
alarm_severity=sev,
alarm_status=status,
alarm_message=msg,
)
store.put_nt("SIM:PRESSURE", p_nt)
spec = [abs(math.sin(2 * math.pi * i / 128 + elapsed * 0.5)) * 100.0
for i in range(128)]
store.put_nt("SIM:SPECTRUM", spvirit.NtScalarArray(spec))
tick += 1
time.sleep(0.5)
except KeyboardInterrupt:
print("\nShutting down.")