01
Overview
A network in AutoTSN is a set of devices with numbered ports, links between two ports, and streams: periodic frames from one talker to one listener along a fixed route. A scheduler turns that into a transmission window for every frame on every link it crosses, and the studio turns the windows into IEEE 802.1Qbv gate control lists. Four JSON documents carry the model through those steps:
- 01Project file.autotsn.jsonThe network as you drew it: devices, ports, links and streams with their routes.
- 02Scheduler requestHTTP POST, JSONThe same network, in the shape the scheduling service reads.
- 03Scheduler responseJSONA transmission window for every frame on every link it crosses.
- 04Gate control liststaprio · YANG · JSONThe windows as IEEE 802.1Qbv gate schedules, per egress port.
Units and conventions
| Frame size | bytes | One Ethernet frame of a stream, as it is scheduled. |
|---|---|---|
| Period, latency, jitter of a stream | µs | Whole microseconds in the scheduler request. |
| Every time in a schedule or gate control list | ns | Measured from the start of the cycle. |
| Line rate of a link | Mbit/s | The studio offers 100 Mbit/s, 1 Gbit/s, 2.5 Gbit/s, 10 Gbit/s. |
- Devices are referred to by their name (
id) everywhere: in links, in streams and in routes. Names are unique. - Ports are named
p0top15. In the scheduler request and the gate control lists a port is writtendevice-port, e.g.sw0-p1. - Links are full duplex. A link direction is written
(u,v): frames leavingutowardsv. Both directions are scheduled independently. - A schedule repeats every cycle. The cycle is the least common multiple of all stream periods (the hyperperiod), or a multiple of it if a scheduler plans a longer horizon.
02
A worked example
Two end stations and a camera on two switches. The camera link runs at 100 Mbit/s, the others at 1 Gbit/s. Stream S1 is a 300-byte control frame every 500 µs; S2 a 1000-byte camera frame every millisecond. The documents below are generated by the studio's own code from this network, so they are exactly what you would get.
Two-switch line
Point at a device, a link or a stream to find it in the document, or point at the document to find it here.
What the studio saves: Project → Save project file. Open it in the studio with Project → Open project file.
03
Topology
The project file is the complete model. It is what Project → Save project file writes and Project → Open project file reads. Its top level:
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| format | string | "autotsn-studio/1" | Format identifier and version of the file. |
| name | string | Name of the network, as shown in the studio's top bar. | |
| nodes | Device[] | Every switch and end station. | |
| edges | Link[] | Every cable between two ports. | |
| streams | Stream[] | Every time-triggered stream, with its route. | |
| gcl | object | null | The gate control lists as edited in step 4, or null. Studio-internal; for tooling use the JSON export of the gate control lists instead. |
Devices
Every entry of nodes is a device. Its kind decides its role: bridges forward frames; end stations talk and listen. End stations may still appear in the middle of a route, for daisy-chained devices with a built-in switch.
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| id | string | [A-Za-z0-9_.-]+ | The device name. Unique in the network; every other reference to the device uses it. |
| typefixed | string | "device" | Always "device". |
| position | { x, y } | canvas px | Where the device sits on the canvas. Layout only; schedulers ignore it. |
| data.kind | string | see device kinds | What the device is. Decides whether it is a bridge (switch) or an end station. |
| data.ports | integer | 1 – 16 | Number of Ethernet ports. The ports are named p0, p1, … p(n−1). |
| kind | Shown as | Role | Default ports | Name prefix |
|---|---|---|---|---|
| switch | Switch | bridge | 4 | sw |
| station | End station | end station | 2 | es |
| hpc | HPC | end station | 4 | HPC- |
| zcu | Zone controller | end station | 4 | ZCU- |
| camera | Camera | end station | 2 | CAM- |
| radio | 5G / telematics | end station | 2 | TCU- |
| drive | Drive ECU | end station | 2 | ECU- |
| sensor | Sensor / actuator | end station | 2 | SA- |
| infotainment | Infotainment | end station | 2 | IVI- |
| cockpit | Cockpit | end station | 2 | CKP- |
Links
Every entry of edges is one cable between a port of one device and a port of another. source and target only record how the cable was drawn; frames use it in both directions.
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| id | string | Unique, opaque identifier of the link. | |
| typefixed | string | "link" | Always "link". |
| source | string | device id | One end of the cable. |
| sourceHandle | string | p0 … p15 | The port used at the source device. |
| target | string | device id | The other end of the cable. |
| targetHandle | string | p0 … p15 | The port used at the target device. |
| data.bandwidth | number | Mbit/s | Line rate of the cable, the same in both directions. The studio offers 100 Mbit/s, 1 Gbit/s, 2.5 Gbit/s, 10 Gbit/s. |
- A port takes exactly one cable.
- Two devices are connected by at most one cable, and no device is linked to itself.
- A port index is always lower than the device's port count.
04
Streams
A stream is one frame of size bytes that the talker sends every period, to exactly one listener, along route. The route is part of the model: a scheduler places frames on it and does not choose paths. When you add a stream, the studio lists the simple paths between talker and listener, shortest first.
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| id | string | S1, S2, … | Unique name of the stream. |
| talker | string | device id | The device that sends the frames. |
| listener | string | device id | The device that receives them. One listener per stream. |
| size | integer | bytes, 1 – 9000 | Length of the one frame the talker sends every period. |
| period | number | µs, > 0 | The talker sends one frame every period. |
| latency | number | µs, > 0 | Upper bound for the end-to-end latency of every frame (definition below). |
| jitter | number | µs, ≥ 0 | Upper bound for the jitter (definition below). 0 asks for strictly periodic transmission. |
| route | string[] | device ids | The path, from talker to listener. Consecutive devices must be linked. The route is part of the model: schedulers place frames on it and do not route. |
How latency and jitter are measured
The studio checks every schedule with the same definitions, whichever engine computed it. Frames are store-and-forward: a bridge starts sending a frame only after it has received all of it. Propagation delay on the cable is not modelled.
- Latency
- For each frame instance: end of its window on the last hop minus start of its window on the first hop. The stream meets its bound if the largest value over all instances in the cycle is at most
latency. - Jitter
- How far consecutive frames drift from the period: the largest |startk − startk−1 − period|, taken on the first hop and on the last hop. 0 means every frame is sent and delivered at exactly the same offset in its period.
05
Scheduler request
When you press Run scheduler with the AutoTSN server selected, the studio sends one HTTP request. The endpoint and the access code come from Settings (the gear icon in the studio). The body is the project, reshaped: the format dates from AutoTSN v1, so some fields are fixed values kept for compatibility.
POST https://api.autotsn.de/schedulerContent-Type: application/json{ "graph": { "nodes": [ … ], "edges": [ … ] }, "streams": [ … ], "userpass": "…", "numofqueues": 0, "numofwindows": 0 }
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| graph | object | The topology: nodes and edges, below. | |
| streams | object[] | One entry per stream, below. | |
| userpass | string | Access code from the studio's Settings. Your own scheduler may ignore it. | |
| numofqueuesfixed | integer | 0 | Reserved. |
| numofwindowsfixed | integer | 0 | Reserved. |
graph.nodes[]: one per device
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| label | string | Device id (node.id). | |
| typefixed | string | "PC" | Sent for switches and end stations alike. |
| precisionfixed | integer | 1 | Reserved. |
graph.edges[]: one per link
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| from | string | Link source (edge.source). | |
| to | string | Link target (edge.target). | |
| fromPort | string | <device>-<port> | Port at the source, e.g. sw0-p1. |
| toPort | string | <device>-<port> | Port at the target, e.g. sw1-p3. |
| bandwidth | number | Mbit/s | Line rate (edge.data.bandwidth). |
| lengthfixed | number | 100 | Reserved. The studio does not model propagation delay. |
| listOfPeriodsfixed | array | [] | Reserved. |
streams[]: one per stream
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| name | string | Stream id. Also sent as Topic. | |
| Topic | string | Same as name. | |
| talkerNode | string | Talker device id. | |
| listenerNode | string | Listener device id. | |
| messageSize | integer | bytes | Frame size plus the frame overhead from Settings (default 0). |
| period | integer | µs | Period, rounded to whole µs. |
| maxLatency | integer | µs | Latency bound, rounded. |
| maxJitter | integer | µs | Jitter bound, rounded. |
| routes | string[][] | A list holding exactly one route: the stream's device list. | |
| routesWithPortsfixed | string[][] | Same as routes. Device ids only, despite the name. | |
| priorityfixed | integer | 0 | Reserved. Traffic classes are chosen in step 4. |
For example, stream S1 of the worked example becomes messageSize 300, period 500, maxLatency 100, maxJitter 5 and routes [["es0", "sw0", "sw1", "es1"]].
06
Scheduler response
The scheduler answers with JSON. Only the fields below are read; anything else is ignored. HTTP 401 or 403 means the access code was refused, 503 that the service is busy; any other error status is shown as a failed run.
| Field | Type | Unit / values | Meaning |
|---|---|---|---|
| status | string | "feasible" | "infeasible" | Whether a schedule was found. |
| message | string | Optional. Shown to the user when the status is infeasible. | |
| timeline | Group[] | The schedule, when feasible: one group per link direction. | |
| timeline[].group | string | "(u,v)" | The link direction: frames leave device u through the port that connects it to v. |
| timeline[].data[].label | string | Stream id. | |
| timeline[].data[].data[].timeRange | [number, number] | ns | Start and end of one transmission window, from the start of the cycle. One window per frame instance. |
| …data[].edge | string | "(u,v)" | Optional. Overrides the group for this window. |
- A window is the time the frame is on the wire on that link direction: from its first to its last bit, so its length is the transmission time at the link's line rate.
- Give one window per frame instance in the cycle: a stream with a 500 µs period in a 1 ms cycle has two windows on each of its links.
- Windows on the same link direction must not overlap.
- The cycle the studio uses is the smallest multiple of the hyperperiod that covers every window.
{"status": "infeasible","message": "No feasible schedule exists for these streams."}
07
Gate control lists
From the windows, the studio builds one gate control list per egress port that carries scheduled frames. Each entry opens a set of gates (traffic classes, PCP 0–7) for a time interval. Scheduled windows open the time-aware traffic classes (PCP 7 by default, changeable in step 4); Autofill gives the remaining time to the other classes and puts a guard band, with all gates closed, before every time-aware window so no best-effort frame is still on the wire when it opens.
| tas | Window computed by the scheduler. Opens the time-aware traffic classes (PCP 7 by default). |
|---|---|
| auto | Best-effort window added by Autofill. Opens every other traffic class. |
| guard | Guard band added by Autofill before a time-aware window. All gates closed. |
| user | Window added or edited by hand. |
The gate mask has bit n set when the gate of traffic class n is open: 0x80 opens only PCP 7, 0x7f opens PCP 0–6, 0x00 closes everything. Traffic classes map one-to-one to PCP values.
Export formats
Linux taprio.sh
One tc qdisc command per egress port. Interval per entry in ns, gate mask in hex, base time, and flags 0x2 for hardware offload.
NETCONF / YANG.xml
ieee802-dot1q-sched gate parameter tables: admin-control-list, admin-cycle-time as a fraction of a second, admin-base-time.
JSON.json
Every entry with start, duration, gate mask, kind and stream, per port. The easiest one to post-process.
# sw0 → sw1 · cycle 1000000 ns · 10 entriestc qdisc replace dev sw0-p1 parent root handle 100 stab overhead 24 taprio \num_tc 8 \map 0 1 2 3 4 5 6 7 0 0 0 0 0 0 0 0 \queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \base-time 0 \sched-entry S 0x00 3400 \sched-entry S 0x80 2400 \sched-entry S 0x7f 60200 \sched-entry S 0x00 15000 \sched-entry S 0x80 8000 \sched-entry S 0x7f 399400 \sched-entry S 0x00 15000 \sched-entry S 0x80 2400 \sched-entry S 0x7f 479200 \sched-entry S 0x00 15000 \flags 0x2
08
Use your own scheduler
There are two ways to bring a network from AutoTSN Studio to another scheduler.
1. Read the project file
Save the project and read it in any language. Everything a scheduler needs is in edges and streams; the transmission time of a frame on a hop is ⌈size · 8000 / line rate⌉ ns.
import json, mathmodel = json.load(open("two-switch-line.autotsn.json"))# Line rate per direction in Mbit/s. Every cable is full duplex.rate = {}for link in model["edges"]:a, b, mbps = link["source"], link["target"], link["data"]["bandwidth"]rate[a, b] = rate[b, a] = mbpsfor s in model["streams"]:hops = list(zip(s["route"], s["route"][1:]))tx_ns = [math.ceil(s["size"] * 8000 / rate[h]) for h in hops]print(f'{s["id"]}: one frame every {s["period"]} µs over {hops}')print(f' transmission per hop {tx_ns} ns, deadline {s["latency"]} µs')
2. Plug your scheduler into the studio
Serve the request and response described above over HTTP, and enter your URL as the endpoint in the studio's Settings. The studio then sends every run to your scheduler and shows its result in the Gantt chart, checks latency and jitter, and builds gate control lists from it. The stub below shows the protocol in about 40 lines of standard-library Python.
# A stub that speaks the AutoTSN scheduler protocol. It is not a real scheduler:# it sends every stream's first frame once, back to back, and ignores periods.import json, mathfrom http.server import BaseHTTPRequestHandler, HTTPServerdef schedule(req):rate = {}for e in req["graph"]["edges"]:rate[e["from"], e["to"]] = rate[e["to"], e["from"]] = e["bandwidth"]groups, t = {}, 0for s in req["streams"]:route = s["routes"][0]for u, v in zip(route, route[1:]):tx = math.ceil(s["messageSize"] * 8000 / rate[u, v]) # nsgroups.setdefault(f"({u},{v})", []).append({"label": s["name"], "data": [{"timeRange": [t, t + tx]}]})t += txreturn {"status": "feasible","timeline": [{"group": g, "data": d} for g, d in groups.items()]}class Handler(BaseHTTPRequestHandler):def cors(self):self.send_header("Access-Control-Allow-Origin", "*")self.send_header("Access-Control-Allow-Methods", "POST, OPTIONS")self.send_header("Access-Control-Allow-Headers", "Content-Type")def do_OPTIONS(self):self.send_response(204)self.cors()self.end_headers()def do_POST(self):req = json.loads(self.rfile.read(int(self.headers["Content-Length"])))body = json.dumps(schedule(req)).encode()self.send_response(200)self.cors()self.send_header("Content-Type", "application/json")self.end_headers()self.wfile.write(body)HTTPServer(("127.0.0.1", 8000), Handler).serve_forever()
- Run it with
python3 stub_scheduler.py, select the AutoTSN server engine, and set the endpoint tohttp://127.0.0.1:8000. - The studio calls your scheduler from the browser, so it must answer CORS preflight requests (the
do_OPTIONSabove) and allow the origin of the studio. - Browsers may ask for your permission before a website talks to a server on your own computer or local network. Allow it for this site.
- A scheduler on another machine should use HTTPS; browsers block plain HTTP requests from an HTTPS page.
09
JSON Schemas
Machine-readable definitions of the three documents (JSON Schema, draft 2020-12), to validate files and generate types. The project file names the format version it was written with in its format field.
- Project filenodes, edges, streamsautotsn-project.schema.json
- Scheduler requestwhat the studio sendsautotsn-scheduler-request.schema.json
- Scheduler responsewhat a scheduler answersautotsn-scheduler-response.schema.json
Questions about the model, or a format your hardware needs?
We build exporters and integrations for TSN tool chains.