Panel rebuilt as the heat matrix: verdict header (ring + newest fault named with its age, cable cell top right), one row per check with NOW / last-90s-at-5s-a-cell / since-reset columns, noise as a blue context lane; history.go keeps the 18-slot wall-time ring (per-class fault deltas, SNR minima, rate verdicts, measuring gray) plus since-reset aggregates and fault ages that clear on reset; noise cycle grid-locked to the shared slot clock so cells never straddle a phase and flicker, presence granted at boot until the first up-phase verdict; check/cross stroked as capsule marks (font has neither), line rate is a pure verdict everywhere, footer is a three-line stat stack beside hold-to-reset; old panel/chip/stat-grid machinery deleted; mockups/ gitignored
This commit is contained in:
@@ -28,8 +28,6 @@ import (
|
||||
const (
|
||||
noiseDriver = "i40e"
|
||||
noiseFrameLen = 1514
|
||||
noiseUpSpan = 5 * time.Second
|
||||
noiseDownSpan = 5 * time.Second
|
||||
noiseFrameGap = 10 * time.Millisecond
|
||||
|
||||
noiseEther uint16 = etherBase + numStreams
|
||||
@@ -94,6 +92,10 @@ func newNoiser() (*noiser, error) {
|
||||
}
|
||||
|
||||
n := &noiser{eps: [2]endpoint{a, b}}
|
||||
// The grid-locked cycle can start mid-down-slot, where absence would be
|
||||
// our own doing: presence is granted until the first up phase delivers a
|
||||
// verdict.
|
||||
n.connected.Store(true)
|
||||
for i, p := range [][2]endpoint{{a, b}, {b, a}} {
|
||||
fd, err := openTxSocket(p[0].idx)
|
||||
if err != nil {
|
||||
@@ -169,6 +171,10 @@ func (n *noiser) bothUp() bool {
|
||||
// comes and goes under the cycle, and a frame this side declined to send is as
|
||||
// good as one the wire mangled. What matters is only ever what the test cable
|
||||
// counted.
|
||||
//
|
||||
// The cycle is locked to the panel's history grid — up on even 5 s slots,
|
||||
// down on odd, transitions on the shared slot boundaries — so a history cell
|
||||
// never straddles a phase and flickers between the two answers.
|
||||
func (n *noiser) run(done *atomic.Bool) {
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
@@ -179,29 +185,27 @@ func (n *noiser) run(done *atomic.Bool) {
|
||||
tick := time.NewTicker(noiseFrameGap)
|
||||
defer tick.Stop()
|
||||
|
||||
applied, wasUp, linked := false, false, false
|
||||
for !done.Load() {
|
||||
n.setLinks(fd, true)
|
||||
n.radiating.Store(true)
|
||||
linked := false
|
||||
for end := time.Now().Add(noiseUpSpan); time.Now().Before(end) && !done.Load(); {
|
||||
<-tick.C
|
||||
if !n.bothUp() {
|
||||
continue
|
||||
}
|
||||
linked = true
|
||||
n.connected.Store(true)
|
||||
for i := range n.ports {
|
||||
unix.Write(n.ports[i].fd, n.ports[i].frame)
|
||||
<-tick.C
|
||||
up := (time.Since(rateEpochStart)/histSlotSpan)%2 == 0
|
||||
if !applied || up != wasUp {
|
||||
// A whole up phase with no link is many times the ~1s the wire
|
||||
// needs to train, so at its end the silence is the cable's answer.
|
||||
if applied && wasUp {
|
||||
n.connected.Store(linked)
|
||||
}
|
||||
n.setLinks(fd, up)
|
||||
n.radiating.Store(up)
|
||||
applied, wasUp, linked = true, up, false
|
||||
}
|
||||
// A whole up phase with no link is many times the ~1s the wire needs
|
||||
// to train, so by now the silence is the cable's answer.
|
||||
n.connected.Store(linked)
|
||||
|
||||
n.setLinks(fd, false)
|
||||
n.radiating.Store(false)
|
||||
for end := time.Now().Add(noiseDownSpan); time.Now().Before(end) && !done.Load(); {
|
||||
<-tick.C
|
||||
if !up || !n.bothUp() {
|
||||
continue
|
||||
}
|
||||
linked = true
|
||||
n.connected.Store(true)
|
||||
for i := range n.ports {
|
||||
unix.Write(n.ports[i].fd, n.ports[i].frame)
|
||||
}
|
||||
}
|
||||
// Left up rather than wherever the cycle stopped, so a run never strands
|
||||
|
||||
Reference in New Issue
Block a user