[General] sim-time-limit = 1s description = "abstract" # enable time synchronization in all network nodes *.*.hasTimeSynchronization = true # all oscillators have a constant drift rate (specified with a random distribution for each one) # except for the master clocks, which have a random drift rate **.tsnClock*.clock.oscillator.typename = "RandomDriftOscillator" **.oscillator.changeInterval = 12.5ms **.oscillator.driftRate = uniform(-100ppm, 100ppm) **.oscillator.driftRateChange = uniform(-1ppm, 1ppm) **.oscillator.driftRateChangeUpperLimit = 100ppm **.oscillator.driftRateChangeLowerLimit = -100ppm # all Ethernet interfaces have 100 Mbps speed *.*.eth[*].bitrate = 100Mbps *.visualizer.typename = "IntegratedMultiCanvasVisualizer" *.visualizer.infoVisualizer[*].displayInfos = true [Config OneMasterClock] network = OneMasterClockGptpShowcase description = "Basic tree topology with one master clock" # Uncomment these lines to test out of band time synchronization using the SimpleClockSynchronizer instead of gPTP #*.tsnClock.gptp.typename = "" #*.*.gptp.typename = "SimpleClockSynchronizer" #*.*.gptp.synchronizationInterval = 0.125s #*.*.gptp.masterClockModule = "^.^.tsnClock.clock" #*.*.gptp.slaveClockModule = "^.clock" # TSN clock gPTP master ports *.tsnClock.gptp.masterPorts = ["eth0"] # TSN switch gPTP bridge master ports *.tsnSwitch.gptp.masterPorts = ["eth1", "eth2"] # Set all reference clocks to master clock so the time difference can be visualized **.referenceClock = "tsnClock.clock" # data link visualizer displays gPTP time synchronization packets *.visualizer.dataLinkVisualizer[0].displayLinks = true *.visualizer.dataLinkVisualizer[0].activityLevel = "protocol" *.visualizer.dataLinkVisualizer[0].packetFilter = "GptpSync" *.visualizer.dataLinkVisualizer[0].lineColor = "blue2" *.visualizer.numInfoVisualizers = 3 *.visualizer.infoVisualizer[0].modules = "*.tsnClock.clock" *.tsnClock.clock.displayStringTextFormat = "time: %T" *.visualizer.infoVisualizer[1].modules = "*.tsnSwitch.clock" *.visualizer.infoVisualizer[1].placementHint = "topLeft" *.visualizer.infoVisualizer[2].modules = "*.tsnDevice*.clock" *.visualizer.infoVisualizer[2].placementHint = "bottom" *.tsnDevice*.clock.displayStringTextFormat = "diff: %d" *.tsnSwitch.clock.displayStringTextFormat = "diff: %d" [Config PrimaryAndHotStandbyMasterClocks] network = TwoMasterClocksTreeGptpShowcase description = "Extended tree topology with two master clocks" # TSN clock2 has a settable clock *.tsnClock2.clock.typename = "SettableClock" *.tsnClock1.gptp.typename = "Gptp" *.tsnClock1.gptp.clockModule = "tsnClock1.clock" *.tsnClock1.gptp.masterPorts = ["eth0"] *.tsnClock2.gptp.typename = "MultiDomainGptp" *.tsnClock2.gptp.numDomains = 2 *.tsnClock2.gptp.domain[*].clockModule = "tsnClock2.clock" *.tsnClock2.gptp.domain[0].gptpNodeType = "SLAVE_NODE" *.tsnClock2.gptp.domain[0].slavePort = "eth0" *.tsnClock2.gptp.domain[1].gptpNodeType = "MASTER_NODE" *.tsnClock2.gptp.domain[1].masterPorts = ["eth0"] # TSN switches have multiple clocks *.tsnSwitch*.clock.typename = "MultiClock" *.tsnSwitch*.clock.numClocks = 2 # TSN switches have multiple gPTP time synchronization domains *.tsnSwitch*.gptp.typename = "MultiDomainGptp" *.tsnSwitch*.gptp.numDomains = 2 *.tsnSwitch1.gptp.domain[0].slavePort = "eth0" *.tsnSwitch1.gptp.domain[0].masterPorts = ["eth1", "eth2", "eth3"] *.tsnSwitch1.gptp.domain[1].slavePort = "eth1" *.tsnSwitch1.gptp.domain[1].masterPorts = ["eth2", "eth3"] # eth1 is omitted because no sync needed towards primary master *.tsnSwitch2.gptp.domain[0].slavePort = "eth1" *.tsnSwitch2.gptp.domain[0].masterPorts = ["eth0", "eth2", "eth3"] *.tsnSwitch2.gptp.domain[1].slavePort = "eth0" *.tsnSwitch2.gptp.domain[1].masterPorts = ["eth1", "eth2", "eth3"] # TSN devices have multiple clocks *.tsnDevice*.clock.typename = "MultiClock" *.tsnDevice*.clock.numClocks = 2 # TSN devices have multiple gPTP time synchronization domains *.tsnDevice*.gptp.typename = "MultiDomainGptp" *.tsnDevice*.gptp.numDomains = 2 *.tsnDevice1.gptp.clockModule = "tsnDevice1.clock" *.tsnDevice2.gptp.clockModule = "tsnDevice2.clock" *.tsnDevice3.gptp.clockModule = "tsnDevice3.clock" *.tsnDevice4.gptp.clockModule = "tsnDevice4.clock" *.tsnDevice*.gptp.domain[*].slavePort = "eth0" # different initial gPTP pdelay measurement and time synchronization offsets **.pdelayInitialOffset = 100us *.*.gptp.domain[0].syncInitialOffset = syncInterval * 1 / 2 *.*.gptp.domain[1].syncInitialOffset = syncInterval * 2 / 2 # set reference clocks so the time difference can be visualized **.clock[0].referenceClock = "tsnClock1.clock" **.clock[1].referenceClock = "tsnClock2.clock" # multiple data link visualizers display different gPTP time synchronization domain packets *.visualizer.numDataLinkVisualizers = 2 *.visualizer.dataLinkVisualizer[*].displayLinks = true *.visualizer.dataLinkVisualizer[*].activityLevel = "protocol" *.visualizer.dataLinkVisualizer[0].packetFilter = expr((has(GptpSync) && GptpSync.domainNumber == 0) || (has(GptpFollowUp) && GptpFollowUp.domainNumber == 0)) *.visualizer.dataLinkVisualizer[1].packetFilter = expr((has(GptpSync) && GptpSync.domainNumber == 1) || (has(GptpFollowUp) && GptpFollowUp.domainNumber == 1)) *.visualizer.dataLinkVisualizer[0].tags = "primary GM" *.visualizer.dataLinkVisualizer[1].tags = "hot-standby GM" *.visualizer.dataLinkVisualizer[0].lineColor = "blue2" *.visualizer.dataLinkVisualizer[1].lineColor = "red2" *.visualizer.numInfoVisualizers = 8 *.visualizer.infoVisualizer[0].modules = "*.tsnDevice*.*.clock[0]" *.visualizer.infoVisualizer[0].textColor = "blue" *.visualizer.infoVisualizer[1].modules = "*.tsnDevice*.*.clock[1]" *.visualizer.infoVisualizer[1].textColor = "red" *.visualizer.infoVisualizer[0..1].placementHint = "bottom" *.visualizer.infoVisualizer[2].modules = "*.tsnClock1.clock" *.visualizer.infoVisualizer[3].modules = "*.tsnClock2.clock" *.visualizer.infoVisualizer[2].textColor = "blue" *.visualizer.infoVisualizer[3].textColor = "red" *.tsnClock*.clock.displayStringTextFormat = "time: %T" *.visualizer.infoVisualizer[4].modules = "*.tsnSwitch1.*.clock[0]" *.visualizer.infoVisualizer[5].modules = "*.tsnSwitch1.*.clock[1]" *.visualizer.infoVisualizer[6].modules = "*.tsnSwitch2.*.clock[0]" *.visualizer.infoVisualizer[7].modules = "*.tsnSwitch2.*.clock[1]" *.visualizer.infoVisualizer[{4,6}].textColor = "blue" *.visualizer.infoVisualizer[{5,7}].textColor = "red" *.tsnDevice*.clock.*.displayStringTextFormat = "diff: %d" *.tsnSwitch*.clock.*.displayStringTextFormat = "diff: %d" *.visualizer.infoVisualizer[4..5].placementHint = "topLeft" *.visualizer.infoVisualizer[6..7].placementHint = "topRight" [Config TwoMasterClocksExploitingNetworkRedundancy] network = TwoMasterClocksRingGptpShowcase description = "Ring topology with redundant time synchronization domains" # clock visualization note: bridge and slave nodes display difference from corresponding master clock # TSN clock2 has multiple clocks *.tsnClock2.clock.typename = "MultiClock" *.tsnClock2.clock.numClocks = 2 # TSN clocks have multiple gPTP time synchronization domains *.tsnClock*.gptp.typename = "MultiDomainGptp" *.tsnClock1.gptp.numDomains = 2 *.tsnClock1.gptp.domain[0..1].clockModule = "tsnClock1.clock" *.tsnClock1.gptp.domain[0].masterPorts = ["eth0"] *.tsnClock1.gptp.domain[1].masterPorts = ["eth0"] *.tsnClock2.gptp.numDomains = 4 *.tsnClock2.gptp.domain[2..3].clockModule = "tsnClock2.clock" *.tsnClock2.gptp.domain[0].gptpNodeType = "SLAVE_NODE" *.tsnClock2.gptp.domain[0].slavePort = "eth0" *.tsnClock2.gptp.domain[1].gptpNodeType = "SLAVE_NODE" *.tsnClock2.gptp.domain[1].slavePort = "eth0" *.tsnClock2.gptp.domain[2].gptpNodeType = "MASTER_NODE" *.tsnClock2.gptp.domain[2].masterPorts = ["eth0"] *.tsnClock2.gptp.domain[3].gptpNodeType = "MASTER_NODE" *.tsnClock2.gptp.domain[3].masterPorts = ["eth0"] # TSN switches have multiple clocks *.tsnSwitch*.clock.typename = "MultiClock" *.tsnSwitch*.clock.numClocks = 4 # TSN switches have multiple gPTP time synchronization domains *.tsnSwitch*.gptp.typename = "MultiDomainGptp" *.tsnSwitch*.gptp.numDomains = 4 # TSN switch 1 *.tsnSwitch1.gptp.domain[0].masterPorts = ["eth1"] *.tsnSwitch1.gptp.domain[0].slavePort = "eth0" *.tsnSwitch1.gptp.domain[1].masterPorts = ["eth2"] *.tsnSwitch1.gptp.domain[1].slavePort = "eth0" *.tsnSwitch1.gptp.domain[2].masterPorts = ["eth1"] *.tsnSwitch1.gptp.domain[2].slavePort = "eth2" *.tsnSwitch1.gptp.domain[3].masterPorts = ["eth2"] *.tsnSwitch1.gptp.domain[3].slavePort = "eth1" # TSN switch 2 *.tsnSwitch2.gptp.domain[0].masterPorts = ["eth1", "eth2"] *.tsnSwitch2.gptp.domain[0].slavePort = "eth0" *.tsnSwitch2.gptp.domain[1].masterPorts = ["eth2"] *.tsnSwitch2.gptp.domain[1].slavePort = "eth1" *.tsnSwitch2.gptp.domain[2].masterPorts = ["eth1", "eth2"] *.tsnSwitch2.gptp.domain[2].slavePort = "eth0" *.tsnSwitch2.gptp.domain[3].masterPorts = ["eth0", "eth2"] *.tsnSwitch2.gptp.domain[3].slavePort = "eth1" # TSN switch 3 *.tsnSwitch3.gptp.domain[0].masterPorts = ["eth1", "eth2"] *.tsnSwitch3.gptp.domain[0].slavePort = "eth0" *.tsnSwitch3.gptp.domain[1].masterPorts = ["eth0", "eth2"] *.tsnSwitch3.gptp.domain[1].slavePort = "eth1" *.tsnSwitch3.gptp.domain[2].masterPorts = ["eth2"] *.tsnSwitch3.gptp.domain[2].slavePort = "eth0" *.tsnSwitch3.gptp.domain[3].masterPorts = ["eth0", "eth2"] *.tsnSwitch3.gptp.domain[3].slavePort = "eth1" # TSN switch 4 *.tsnSwitch4.gptp.domain[0].masterPorts = ["eth0", "eth2"] *.tsnSwitch4.gptp.domain[0].slavePort = "eth1" *.tsnSwitch4.gptp.domain[1].masterPorts = ["eth0", "eth1"] *.tsnSwitch4.gptp.domain[1].slavePort = "eth2" *.tsnSwitch4.gptp.domain[2].masterPorts = ["eth2"] *.tsnSwitch4.gptp.domain[2].slavePort = "eth0" *.tsnSwitch4.gptp.domain[3].masterPorts = ["eth1"] *.tsnSwitch4.gptp.domain[3].slavePort = "eth0" # TSN switch 5 *.tsnSwitch5.gptp.domain[0].masterPorts = ["eth1", "eth2"] *.tsnSwitch5.gptp.domain[0].slavePort = "eth0" *.tsnSwitch5.gptp.domain[1].masterPorts = ["eth0", "eth2"] *.tsnSwitch5.gptp.domain[1].slavePort = "eth1" *.tsnSwitch5.gptp.domain[2].masterPorts = ["eth1", "eth2"] *.tsnSwitch5.gptp.domain[2].slavePort = "eth0" *.tsnSwitch5.gptp.domain[3].masterPorts = ["eth2"] *.tsnSwitch5.gptp.domain[3].slavePort = "eth1" # TSN switch 6 *.tsnSwitch6.gptp.domain[0].masterPorts = ["eth2"] *.tsnSwitch6.gptp.domain[0].slavePort = "eth0" *.tsnSwitch6.gptp.domain[1].masterPorts = ["eth0", "eth2"] *.tsnSwitch6.gptp.domain[1].slavePort = "eth1" *.tsnSwitch6.gptp.domain[2].masterPorts = ["eth1", "eth2"] *.tsnSwitch6.gptp.domain[2].slavePort = "eth0" *.tsnSwitch6.gptp.domain[3].masterPorts = ["eth0", "eth2"] *.tsnSwitch6.gptp.domain[3].slavePort = "eth1" # TSN devices have multiple clocks *.tsnDevice*.clock.typename = "MultiClock" *.tsnDevice*.clock.numClocks = 4 # TSN devices have multiple gPTP time synchronization domains *.tsnDevice*.gptp.typename = "MultiDomainGptp" *.tsnDevice*.gptp.numDomains = 4 *.tsnDevice1.gptp.clockModule = "tsnDevice1.clock" *.tsnDevice2.gptp.clockModule = "tsnDevice2.clock" *.tsnDevice3.gptp.clockModule = "tsnDevice3.clock" *.tsnDevice4.gptp.clockModule = "tsnDevice4.clock" *.tsnDevice*.gptp.domain[*].slavePort = "eth0" # different initial gPTP pdelay measurement and time synchronization offsets **.pdelayInitialOffset = 0.1ms *.*.gptp.domain[0].syncInitialOffset = syncInterval * 1 / 4 *.*.gptp.domain[1].syncInitialOffset = syncInterval * 2 / 4 *.*.gptp.domain[2].syncInitialOffset = syncInterval * 3 / 4 *.*.gptp.domain[3].syncInitialOffset = syncInterval * 4 / 4 # multiple data link visualizers display different gPTP time synchronization domain packets *.visualizer.typename = "IntegratedMultiCanvasVisualizer" *.visualizer.numDataLinkVisualizers = 4 *.visualizer.dataLinkVisualizer[*].displayLinks = true *.visualizer.dataLinkVisualizer[*].activityLevel = "protocol" *.visualizer.dataLinkVisualizer[0].packetFilter = expr(has(GptpSync) && GptpSync.domainNumber == 0) *.visualizer.dataLinkVisualizer[1].packetFilter = expr(has(GptpSync) && GptpSync.domainNumber == 1) *.visualizer.dataLinkVisualizer[2].packetFilter = expr(has(GptpSync) && GptpSync.domainNumber == 2) *.visualizer.dataLinkVisualizer[3].packetFilter = expr(has(GptpSync) && GptpSync.domainNumber == 3) *.visualizer.dataLinkVisualizer[0].tags = "primary GM domain0" *.visualizer.dataLinkVisualizer[1].tags = "primary GM domain1" *.visualizer.dataLinkVisualizer[2].tags = "hot-standby GM domain0" *.visualizer.dataLinkVisualizer[3].tags = "hot-standby GM domain1" *.visualizer.dataLinkVisualizer[0].lineColor = "blue4" *.visualizer.dataLinkVisualizer[1].lineColor = "blue1" *.visualizer.dataLinkVisualizer[2].lineColor = "red4" *.visualizer.dataLinkVisualizer[3].lineColor = "red1" *.tsnClock1.clock.referenceClock = "tsnClock1.clock" # so how does it sync to domain1? *.tsnClock2.clock.clock[*].referenceClock = "tsnClock1.clock" *.tsnSwitch*.clock.clock[0..1].referenceClock = "tsnClock1.clock" *.tsnDevice*.clock.clock[0..1].referenceClock = "tsnClock1.clock" *.tsnSwitch*.clock.clock[2..3].referenceClock = "tsnClock2.clock.clock[1]" *.tsnDevice*.clock.clock[2..3].referenceClock = "tsnClock2.clock.clock[1]" *.tsnSwitch*.clock.clock[*].displayStringTextFormat = "%d" *.tsnDevice*.clock.clock[*].displayStringTextFormat = "%d" *.tsnClock1.clock.displayStringTextFormat = "time: %T" *.tsnClock2.clock.clock*.displayStringTextFormat = "time: %T\ndiff: %d" *.visualizer.numInfoVisualizers = 11 *.visualizer.infoVisualizer[0].modules = "*.tsnClock1.clock" *.visualizer.infoVisualizer[0].textColor = "blue4" *.visualizer.infoVisualizer[1].modules = "*.tsnSwitch1.*.clock[0] or *.tsnSwitch2.*.clock[0] or *.tsnSwitch6.*.clock[0] or *.tsnDevice1.*.clock[0] or *.tsnDevice4.*.clock[0]" *.visualizer.infoVisualizer[1].textColor = "blue4" *.visualizer.infoVisualizer[2].modules = "*.tsnSwitch1.*.clock[1] or *.tsnSwitch2.*.clock[1] or *.tsnSwitch6.*.clock[1] or *.tsnDevice1.*.clock[1] or *.tsnDevice4.*.clock[1]" *.visualizer.infoVisualizer[2].textColor = "blue1" *.visualizer.infoVisualizer[3].modules = "*.tsnSwitch1.*.clock[2] or *.tsnSwitch2.*.clock[2] or *.tsnSwitch6.*.clock[2] or *.tsnDevice1.*.clock[2] or *.tsnDevice4.*.clock[2]" *.visualizer.infoVisualizer[3].textColor = "red4" *.visualizer.infoVisualizer[4].modules = "*.tsnSwitch1.*.clock[3] or *.tsnSwitch2.*.clock[3] or *.tsnSwitch6.*.clock[3] or *.tsnDevice1.*.clock[3] or *.tsnDevice4.*.clock[3]" *.visualizer.infoVisualizer[4].textColor = "red1" *.visualizer.infoVisualizer[5].modules = "*.tsnDevice2.*.clock[0] or *.tsnDevice3.*.clock[0] or *.tsnSwitch3.*.clock[0] or *.tsnSwitch4.*.clock[0] or *.tsnSwitch5.*.clock[0]" *.visualizer.infoVisualizer[5].textColor = "blue4" *.visualizer.infoVisualizer[6].modules = "*.tsnDevice2.*.clock[1] or *.tsnDevice3.*.clock[1] or *.tsnSwitch3.*.clock[1] or *.tsnSwitch4.*.clock[1] or *.tsnSwitch5.*.clock[1]" *.visualizer.infoVisualizer[6].textColor = "blue1" *.visualizer.infoVisualizer[7].modules = "*.tsnDevice2.*.clock[2] or *.tsnDevice3.*.clock[2] or *.tsnSwitch3.*.clock[2] or *.tsnSwitch4.*.clock[2] or *.tsnSwitch5.*.clock[2]" *.visualizer.infoVisualizer[7].textColor = "red4" *.visualizer.infoVisualizer[8].modules = "*.tsnDevice2.*.clock[3] or *.tsnDevice3.*.clock[3] or *.tsnSwitch3.*.clock[3] or *.tsnSwitch4.*.clock[3] or *.tsnSwitch5.*.clock[3]" *.visualizer.infoVisualizer[8].textColor = "red1" *.visualizer.infoVisualizer[9].modules = "*.tsnClock2.*.clock[0]" *.visualizer.infoVisualizer[9].textColor = "red4" *.visualizer.infoVisualizer[10].modules = "*.tsnClock2.*.clock[1]" *.visualizer.infoVisualizer[10].textColor = "red1" *.visualizer.infoVisualizer[5..10].placementHint = "bottom"