Cable verdict folded into one console cell (length green, fault name red, xover amber, fail; diag rule lines and counters-reset line gone), reset fires at the press not diag completion, and the measure's blip is suppressed at every counter source instead of counted-hidden-reverted: worker error adds, loss-window write-offs (quiet slides state without charging; leaving the quiet era presumes in-window holes delivered so the gap's tail is never charged late), NIC poller tracks raw without accumulating, socket drops discarded, modules un-primed by the measure itself; display hold deleted so pre-existing errors no longer blink out during a measure
This commit is contained in:
@@ -769,6 +769,15 @@ func (m *phyModule) reset() {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Latches drained after a measure belong to its blip: un-priming makes the
|
||||
// next poll an origin only, without discarding the pre-measure totals.
|
||||
func (m *phyModule) forgive() {
|
||||
m.mu.Lock()
|
||||
m.primed = false
|
||||
m.recentDelta = 0
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
type phyModView struct {
|
||||
fresh bool
|
||||
link bool
|
||||
@@ -802,6 +811,7 @@ type cableInfo struct {
|
||||
ecd ecdResult
|
||||
maps [2]byte
|
||||
haveMaps [2]bool
|
||||
failed bool
|
||||
}
|
||||
|
||||
func (c cableInfo) metresString() string {
|
||||
@@ -845,8 +855,6 @@ type phyDisplay struct {
|
||||
metresClass int
|
||||
}
|
||||
|
||||
func pairLetter(i int) string { return string(rune('A' + i)) }
|
||||
|
||||
// Each end resolves MDI on its own, so a swap at either known end counts; an
|
||||
// end with no readable map abstains.
|
||||
func pairSwapped(i int, c cableInfo) bool {
|
||||
@@ -858,32 +866,35 @@ func pairSwapped(i int, c cableInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// The whole cable verdict in one cell: the length when healthy, the first
|
||||
// faulted pair's verdict when not, "xover" for a pair swap, "fail" for a diag
|
||||
// that never delivered.
|
||||
func cableSummary(cable cableInfo, measuring bool) (string, int) {
|
||||
if measuring {
|
||||
return "...", clsNone
|
||||
return "-", clsNone
|
||||
}
|
||||
anyData, anyFault, anySwap := false, false, false
|
||||
if cable.failed {
|
||||
return "fail", clsBad
|
||||
}
|
||||
anyData, anySwap := false, false
|
||||
for i, v := range cable.ecd.verdicts {
|
||||
if v != 0 {
|
||||
anyData = true
|
||||
}
|
||||
if v != 0 && v != pairOK {
|
||||
anyFault = true
|
||||
return pairVerdicts[v], clsBad
|
||||
}
|
||||
if pairSwapped(i, cable) {
|
||||
anySwap = true
|
||||
}
|
||||
}
|
||||
s := cable.metresString()
|
||||
switch {
|
||||
case !anyData:
|
||||
return "-", clsNone
|
||||
case anyFault:
|
||||
return s, clsBad
|
||||
case anySwap:
|
||||
return s, clsWarn
|
||||
return "xover", clsWarn
|
||||
}
|
||||
return s, clsGood
|
||||
return cable.metresString(), clsGood
|
||||
}
|
||||
|
||||
// The margin is the worst pair across the ends that measure SNR (the Wiitek's
|
||||
@@ -977,6 +988,7 @@ func measureCable(mods []*phyModule, waitRelink bool, done *atomic.Bool) (cableI
|
||||
}
|
||||
defer func() {
|
||||
for _, m := range mods {
|
||||
m.forgive()
|
||||
m.busy.Store(false)
|
||||
}
|
||||
}()
|
||||
@@ -1010,83 +1022,45 @@ func measureCable(mods []*phyModule, waitRelink bool, done *atomic.Bool) (cableI
|
||||
}
|
||||
|
||||
type cableDiag struct {
|
||||
mods []*phyModule
|
||||
completed chan error
|
||||
mods []*phyModule
|
||||
|
||||
mu sync.Mutex
|
||||
info cableInfo
|
||||
running bool
|
||||
// While set, every failure counter is suppressed at its source: the
|
||||
// measure's own link blip is never counted anywhere, rather than counted,
|
||||
// hidden and reverted.
|
||||
measuring atomic.Bool
|
||||
|
||||
mu sync.Mutex
|
||||
info cableInfo
|
||||
}
|
||||
|
||||
func newCableDiag(mods []*phyModule, info cableInfo) *cableDiag {
|
||||
return &cableDiag{mods: mods, completed: make(chan error, 1), info: info}
|
||||
return &cableDiag{mods: mods, info: info}
|
||||
}
|
||||
|
||||
func (c *cableDiag) snapshot() (cableInfo, bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.info, c.running
|
||||
return c.info, c.measuring.Load()
|
||||
}
|
||||
|
||||
func (c *cableDiag) kick(done *atomic.Bool) bool {
|
||||
c.mu.Lock()
|
||||
if c.running {
|
||||
c.mu.Unlock()
|
||||
if !c.measuring.CompareAndSwap(false, true) {
|
||||
return false
|
||||
}
|
||||
c.running = true
|
||||
c.mu.Unlock()
|
||||
|
||||
go func() {
|
||||
defer holdPanic()
|
||||
info, _, err := measureCable(c.mods, true, done)
|
||||
if err != nil {
|
||||
info = cableInfo{}
|
||||
info = cableInfo{failed: true}
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.info = info
|
||||
c.running = false
|
||||
c.mu.Unlock()
|
||||
select {
|
||||
case c.completed <- err:
|
||||
default:
|
||||
}
|
||||
c.measuring.Store(false)
|
||||
}()
|
||||
return true
|
||||
}
|
||||
|
||||
func mapString(m byte, have bool) string {
|
||||
if !have {
|
||||
return "unread"
|
||||
}
|
||||
if m == pairIdentityMap {
|
||||
return "straight"
|
||||
}
|
||||
out := make([]string, 4)
|
||||
for i := range out {
|
||||
out[i] = pairLetter(int(m>>(2*i)) & 3)
|
||||
}
|
||||
return "swapped to " + strings.Join(out, "")
|
||||
}
|
||||
|
||||
func verdictString(r ecdResult) string {
|
||||
bad := []string{}
|
||||
for i, v := range r.verdicts {
|
||||
if v != pairOK {
|
||||
s, ok := pairVerdicts[v]
|
||||
if !ok {
|
||||
s = fmt.Sprintf("%d", v)
|
||||
}
|
||||
bad = append(bad, fmt.Sprintf("%s %s at %dm", pairLetter(i), s, r.metres[i]))
|
||||
}
|
||||
}
|
||||
if len(bad) > 0 {
|
||||
return strings.Join(bad, ", ")
|
||||
}
|
||||
return fmt.Sprintf("all pairs ok, %d/%d/%d/%d m",
|
||||
r.metres[0], r.metres[1], r.metres[2], r.metres[3])
|
||||
}
|
||||
|
||||
func openModules(names [2]string) ([]*phyModule, [2]string, error) {
|
||||
mods := make([]*phyModule, 0, 2)
|
||||
var idents [2]string
|
||||
@@ -1218,7 +1192,3 @@ func moduleChecks(mods []*phyModule, names [2]string) []checkResult {
|
||||
return out
|
||||
}
|
||||
|
||||
func cableLine(c cableInfo) string {
|
||||
return fmt.Sprintf("%s; map %s / %s",
|
||||
verdictString(c.ecd), mapString(c.maps[0], c.haveMaps[0]), mapString(c.maps[1], c.haveMaps[1]))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user