package wsjtx import ( "strconv" "strings" "time" "github.com/mmcloughlin/geohash" "github.com/tzneal/ham-go/dxcc" log "github.com/sirupsen/logrus" ) type Row struct { Time time.Time Bandf float64 Direction string Mode string Strength int Offset float64 Freq string First string Second string Third string Fourth string } type Result struct { Station string Identifier string Ent dxcc.Entity Call string Grid string Band string Mode string Signal int GeoHash string Timestamp time.Time Rx int } var blackList = map[string]bool { "73": true, "RR73;": true, "GL": true, "TNX": true, "<...>": true, "QSO": true, "QSY": true, "TIME": true, "TIMESYNC": true, } func GetBand(freq float64) (string){ band := "unknown" if (freq>1 && freq<2) { band = "160m" } if (freq>3 && freq<4) { band = "80m" } if (freq>5 && freq<6) { band = "60m" } if (freq>7.0 && freq<8.0) { band = "40m" } if (freq>10 && freq<11) { band = "30m" } if (freq>14 && freq<15) { band = "20m" } if (freq>18 && freq<19) { band = "17m" } if (freq>21 && freq<22) { band = "15m" } if (freq>24 && freq<25) { band = "12m" } if (freq>28 && freq<30) { band = "10m" } if (freq>144 && freq<145) { band = "2m" } if (freq>432 && freq<433){ band = "70cm" } return band } func ScanLine(line string) (Result, bool) { var err error var tmp string element := new(Row) result := new(Result) found := false // dont fail on too short lines if len(line) < 16 { log.WithFields(log.Fields{"line":line}).Error("line too short") return *result, false } // parse only lines in new format, because old format misses band if line[6] == '_' && line[15] != 'T' { dataSlice := strings.Fields(line) for i, v := range dataSlice { switch i { case 0: element.Time, err = time.Parse("060102_150405",v) if err != nil { log.WithFields(log.Fields{"err":err}).Trace("something went wrong while parsing the timestamp: ",v) return *result, false } case 1: element.Bandf,_ = strconv.ParseFloat(v,10) case 2: element.Direction = v case 3: element.Mode = v case 4: element.Strength,_ = strconv.Atoi(v) case 5: element.Offset,_ = strconv.ParseFloat(v,10) case 6: element.Freq = v case 7: element.First= v case 8: element.Second= v case 9: element.Third = v case 10: element.Fourth = v default: log.WithFields(log.Fields{"line":line}).Trace("can't parse line..") } } // check for 4 element sequence like 'CQ DX DL3SD JO31' if element.Fourth != "" { result.Call = element.Third log.WithFields(log.Fields{"line":line,"callsign":result.Call}).Trace("parsed 4 element callsign") } else { result.Call = element.Second } // ignore 'TNX QSO GL 73' etc. if blackList[result.Call] { log.WithFields(log.Fields{"line":line,"callsign":result.Call}).Trace("skipping callsign") return *result, false } // take care of Calls like / FIXME does this actually work? tmp = strings.Replace(result.Call, "<", "", -1) result.Call = strings.Replace(tmp, ">", "", -1) result.Band = GetBand(element.Bandf) result.Ent, found = dxcc.Lookup(result.Call) // FIXME this is where the expensive stuff happens and should be cached.. // FIXME result.Grid = qrz.lookup(result.Call) ;) or track in ALL.txt ^^ if found && result.Band != "unknown" { result.Signal = element.Strength result.Mode = element.Mode // FIXME // * get better grid, see above // * build geohash from better grid with gpsfromgrid(result.Grid) result.GeoHash = geohash.Encode(result.Ent.Latitude, result.Ent.Longitude) result.Timestamp = element.Time if element.Direction[0] == 'R' { result.Rx = 1 } else { result.Rx = 0 result.Grid = element.Third } log.WithFields(log.Fields{ "call":result.Call, "signal":result.Signal, "dxcc":result.Ent.DXCC, "continent":result.Ent.Continent, "band":result.Band, "sendtime":result.Timestamp, "mode":result.Mode, "geohash":result.GeoHash, "rx":result.Rx, }).Trace("successfully parsed line") return *result, true } else { if !found { log.WithFields(log.Fields{"line":line,"callsign":element.Second}).Trace("cant parse callsign") } else if result.Band == "unknown" { log.WithFields(log.Fields{"line":line,"band":result.Band}).Trace("cant parse band") } else { log.WithFields(log.Fields{"line":line}).Error("something really strange happened..") } } } else { // log.WithFields(log.Fields{"line":line}).Info("found old formated line..") } return *result, false }