func updateDownstream(n *html.Node) map[modem.Channel]*downstreamStat { glog.V(2).Infoln("Updating downstream table") stats := map[modem.Channel]*downstreamStat{} var ids []modem.Channel // Remove nested tables for _, t := range cascadia.MustCompile("table table").MatchAll(n) { t.Parent.RemoveChild(t) } for row, tr := range cascadia.MustCompile("tr").MatchAll(n)[1:] { switch row { case 0: // ID for _, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { id := modem.Channel(htmlutil.GetText(td)) ids = append(ids, id) stats[id] = &downstreamStat{} } case 1: // Frequency for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { stats[ids[i]].frequency = strings.Fields(htmlutil.GetText(td))[0] } case 2: // SNR for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { f, err := strconv.ParseFloat(strings.Fields(htmlutil.GetText(td))[0], 64) if err != nil { continue } stats[ids[i]].snr = f } case 3: // Modulation for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { stats[ids[i]].modulation = htmlutil.GetText(td) } case 4: for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { // Power level f, err := strconv.ParseFloat(strings.Fields(htmlutil.GetText(td))[0], 64) if err != nil { continue } stats[ids[i]].powerLevel = f } default: glog.Fatalf("Unhandled %d row in downstream table", row) } } return stats }
func updateSignalStats(n *html.Node) map[modem.Channel]*downstreamErrorStat { glog.V(2).Infoln("Updating signal stats table") stats := map[modem.Channel]*downstreamErrorStat{} var ids []modem.Channel for row, tr := range cascadia.MustCompile("tr").MatchAll(n)[1:] { switch row { case 0: // ID for _, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { id := modem.Channel(htmlutil.GetText(td)) ids = append(ids, id) stats[id] = &downstreamErrorStat{} } case 1: // Total Unerrored Codewords for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { f, err := strconv.ParseFloat(strings.Fields(htmlutil.GetText(td))[0], 64) if err != nil { continue } stats[ids[i]].unerrored = f } case 2: // Total Correctable Codewords for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { f, err := strconv.ParseFloat(strings.Fields(htmlutil.GetText(td))[0], 64) if err != nil { continue } stats[ids[i]].correctable = f } case 3: // Total Uncorrectable Codewords for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { f, err := strconv.ParseFloat(strings.Fields(htmlutil.GetText(td))[0], 64) if err != nil { continue } stats[ids[i]].uncorrectable = f } default: glog.Fatalf("Unhandled %d row in signal stats table", row) } } return stats }
func updateUpstream(n *html.Node) map[modem.Channel]*upstreamStat { glog.V(2).Infoln("Updating upstream table") stats := map[modem.Channel]*upstreamStat{} var ids []modem.Channel for row, tr := range cascadia.MustCompile("tr").MatchAll(n)[1:] { switch row { case 0: // ID for _, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { id := modem.Channel(htmlutil.GetText(td)) ids = append(ids, id) stats[id] = &upstreamStat{} } case 1: // Frequency for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { stats[ids[i]].frequency = strings.Fields(htmlutil.GetText(td))[0] } case 2: // Ranging Service ID for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { stats[ids[i]].rangingService = htmlutil.GetText(td) } case 3: // Symbol Rate for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { f, err := strconv.ParseFloat(strings.Fields(htmlutil.GetText(td))[0], 64) if err != nil { continue } stats[ids[i]].symbolRate = f * 1000000 } case 4: // Power level for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { f, err := strconv.ParseFloat(strings.Fields(htmlutil.GetText(td))[0], 64) if err != nil { continue } stats[ids[i]].powerLevel = f } case 5: // Modulation for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { stats[ids[i]].modulation = strings.Replace(htmlutil.GetText(td), "\n", " ", -1) } case 6: // Ranging Status for i, td := range cascadia.MustCompile("td").MatchAll(tr)[1:] { stats[ids[i]].rangingStatus = htmlutil.GetText(td) } default: glog.Fatalf("Unhandled %d row in upstream table", row) } } return stats }
func parseDownstreamTable(n *html.Node) (map[modem.Channel]*modem.Downstream, error) { m := map[modem.Channel]*modem.Downstream{} rows := cascadia.MustCompile("tr").MatchAll(n) if len(rows) <= 2 { return nil, fmt.Errorf("Expected more than 2 row in table, got %d", len(rows)) } for _, row := range rows[2:] { d := &modem.Downstream{} var ch modem.Channel for i, col := range cascadia.MustCompile("td").MatchAll(row) { v := htmlutil.GetText(col) fv := v if idx := strings.Index(v, " "); idx != -1 { fv = fv[:idx] } f, _ := strconv.ParseFloat(fv, 64) switch i { case 0: // Channel ch = modem.Channel(v) case 1: // Lock Status case 2: // Modulation d.Modulation = v case 3: // Channel ID case 4: // Frequency (Hz) d.Frequency = v case 5: // Power (dBmV) d.PowerLevel = f case 6: // SNR (dB) d.SNR = f case 7: // Corrected d.Correctable = f case 8: // Uncorrectables d.Uncorrectable = f default: glog.Errorf("Unexpected %dth column in downstream table", i) } } m[ch] = d } return m, nil }