// MaybeAdd looks at a new message, and updates the buffer as appropriate. func (mb *MsgBuffer) Add(m *adsb.Msg) { mb.ageOutQuietSenders() if _, exists := mb.Senders[m.Icao24]; exists == false { // We've not seen this sender before. If we have position data, // start the whitelisting thing. We only Whitelist senders who // will eventually send useful info (e.g. position), so wait until // we see that. if m.HasPosition() { mb.Senders[m.Icao24] = &ADSBSender{LastSeen: time.Now().UTC()} } } else { mb.Senders[m.Icao24].updateFromMsg(m) // Pluck out anything interesting if composite := mb.Senders[m.Icao24].maybeCreateComposite(m); composite != nil { // We have a message to store !! mb.Messages = append(mb.Messages, composite) } } // We use the timestamp in the message to decide when to flush, // rather than the time at which we received the message; this is to // deliver a better end-to-end QoS for message delivery. // But stale messages can arrive, with timestamps from the past; // they would always trigger a flush, and flushing every message // slows things down (so we never ever catch up again :(). // So we also enforce a minimum interval between flushes. if len(mb.Messages) > 0 { t := mb.Messages[0].GeneratedTimestampUTC if time.Since(t) >= mb.MaxMessageAge && time.Since(mb.lastFlush) >= mb.MinPublishInterval { mb.flush() } } }
func main() { Log.Printf("reading file '%s' (dumpPos=%v)", fFilename, fDumpPos) h := histogram.Histogram{ ValMin: 0, ValMax: 80, NumBuckets: 80, } _ = h if osFile, err := os.Open(fFilename); err != nil { Log.Fatal(err) } else { scanner := bufio.NewScanner(osFile) // os.File implements io.Reader for scanner.Scan() { m := adsb.Msg{} text := scanner.Text() if err := m.FromSBS1(text); err != nil { Log.Fatal(err) break } if fDumpPos { if m.HasPosition() { fmt.Printf("\"%.5f,%.5f\"\n", m.Position.Lat, m.Position.Long) } } else { Log.Print(m) } } if err := scanner.Err(); err != nil { Log.Fatal(err) } } }
// If this message has new position info, *and* we have good backfill, then craft a CompositeMsg. // Note, we don't wait for squawk info. func (s *ADSBSender) maybeCreateComposite(m *adsb.Msg) *adsb.CompositeMsg { if !m.HasPosition() { return nil } //if s.LastGroundSpeed == 0 || s.LastTrack == 0 || s.LastCallsign == "" { return nil } cm := adsb.CompositeMsg{Msg: *m} // Clone the input into the embedded struct // Overwrite with cached info (from previous packets), if we don't have it in this packet if cm.GroundSpeed == 0 { cm.GroundSpeed = s.LastGroundSpeed } if cm.VerticalRate == 0 { cm.VerticalRate = s.LastVerticalSpeed } if cm.Track == 0 { cm.Track = s.LastTrack } if cm.Callsign == "" { cm.Callsign = s.LastCallsign } if cm.Squawk == "" { cm.Squawk = s.LastSquawk } return &cm }