diff --git a/main/gen_gdl90.go b/main/gen_gdl90.go index 6daedc97..f4fedaed 100755 --- a/main/gen_gdl90.go +++ b/main/gen_gdl90.go @@ -745,10 +745,15 @@ type WeatherMessage struct { Time string Data string LocaltimeReceived time.Time + Ticks int64 + TowerLon float64 + TowerLat float64 + TisId byte + } // Send update to connected websockets. -func registerADSBTextMessageReceived(msg string) { +func registerADSBTextMessageReceived(msg string, uatMsg *uatparse.UATMsg) { x := strings.Split(msg, " ") if len(x) < 5 { return @@ -768,13 +773,25 @@ func registerADSBTextMessageReceived(msg string) { if x[0] == "PIREP" { globalStatus.UAT_PIREP_total++ } - - wm.Type = x[0] - wm.Location = x[1] - wm.Time = x[2] - wm.Data = strings.Join(x[3:], " ") + if x[0] == "NEXRAD" { + log.Printf("registerADSBTextMessageReceived: %s\n",msg) + wm.Type = x[0] + wm.Data = strings.Join(x[1:], " ") + wm.Location = "NEXRAD" + wm.Time = "NONE" + } else { + wm.Type = x[0] + wm.Location = x[1] + wm.Time = x[2] + wm.Data = strings.Join(x[3:], " ") + } wm.LocaltimeReceived = stratuxClock.Time - + wm.TowerLon = uatMsg.Lon + wm.TowerLat = uatMsg.Lat +// now := time.Now() +// Year := time.Year() + uatTime := time.Date(2016, time.Month(uatMsg.Frames[0].FISB_month),int(uatMsg.Frames[0].FISB_day), int(uatMsg.Frames[0].FISB_hours), int(uatMsg.Frames[0].FISB_minutes), int(uatMsg.Frames[0].FISB_seconds), 0, time.UTC) + wm.Ticks = uatTime.UnixNano() / 1000000 wmJSON, _ := json.Marshal(&wm) // Send to weatherUpdate channel for any connected clients. @@ -895,7 +912,7 @@ func parseInput(buf string) ([]byte, uint16) { // Get all of the text reports. textReports, _ := uatMsg.GetTextReports() for _, r := range textReports { - registerADSBTextMessageReceived(r) + registerADSBTextMessageReceived(r, uatMsg) } thisMsg.uatMsg = uatMsg } diff --git a/main/managementinterface.go b/main/managementinterface.go old mode 100644 new mode 100755 index 290a10b3..cdd035fa --- a/main/managementinterface.go +++ b/main/managementinterface.go @@ -57,6 +57,35 @@ func handleWeatherWS(conn *websocket.Conn) { } } +func handleJsonIo(conn *websocket.Conn) { + trafficMutex.Lock() + for _, traf := range traffic { + if !traf.Position_valid { // Don't send unless a valid position exists. + continue + } + trafficJSON, _ := json.Marshal(&traf) + conn.Write(trafficJSON) + } + // Subscribe the socket to receive updates. + trafficUpdate.AddSocket(conn) + weatherUpdate.AddSocket(conn) + + trafficMutex.Unlock() + + // Connection closes when function returns. Since uibroadcast is writing and we don't need to read anything (for now), just keep it busy. + for { + buf := make([]byte, 1024) + _, err := conn.Read(buf) + if err != nil { + break + } + if buf[0] != 0 { // Dummy. + continue + } + time.Sleep(1 * time.Second) + } +} + // Works just as weather updates do. func handleTrafficWS(conn *websocket.Conn) { @@ -512,6 +541,13 @@ func managementInterface() { s.ServeHTTP(w, req) }) + http.HandleFunc("/jsonio", + func(w http.ResponseWriter, req *http.Request) { + s := websocket.Server{ + Handler: websocket.Handler(handleJsonIo)} + s.ServeHTTP(w, req) + }) + http.HandleFunc("/getStatus", handleStatusRequest) http.HandleFunc("/getSituation", handleSituationRequest) http.HandleFunc("/getTowers", handleTowersRequest) diff --git a/main/traffic.go b/main/traffic.go old mode 100644 new mode 100755 index 26addc3d..e7c4e216 --- a/main/traffic.go +++ b/main/traffic.go @@ -75,6 +75,7 @@ const ( ) type TrafficInfo struct { + Type string // Icao_addr uint32 Reg string // Registration. Calculated from Icao_addr for civil aircraft of US registry. Tail string // Callsign. Transmitted by aircraft. diff --git a/uatparse/uatparse.go b/uatparse/uatparse.go old mode 100644 new mode 100755 index 6dc2e985..6197bc92 --- a/uatparse/uatparse.go +++ b/uatparse/uatparse.go @@ -4,11 +4,13 @@ import ( "encoding/hex" "errors" "fmt" + "log" "io/ioutil" "strconv" "strings" ) +var elementIdentifier byte const ( UPLINK_BLOCK_DATA_BITS = 576 UPLINK_BLOCK_BITS = (UPLINK_BLOCK_DATA_BITS + 160) @@ -24,7 +26,9 @@ const ( // assume 6 byte frames: 2 header bytes, 4 byte payload // (TIS-B heartbeat with one address, or empty FIS-B APDU) UPLINK_MAX_INFO_FRAMES = (424 / 6) - + COLS_PER_BIN = 32 + ROWS_PER_BIN = 4 + dlac_alpha = "\x03ABCDEFGHIJKLMNOPQRSTUVWXYZ\x1A\t\x1E\n| !\"#$%&'()*+,-./0123456789:;<=>?" ) @@ -187,6 +191,123 @@ func formatDLACData(p string) []string { return ret } +func (f *UATFrame) decodeNexradFrame() { + ret := make([]string, 0) + builder := make([]string, 0) + + if len(f.FISB_data) < int(f.FISB_length) { + return + } + mEmpty := make([]int32, 1) + mData := make([]int32, COLS_PER_BIN * ROWS_PER_BIN) + elementIdentifier := f.FISB_data[0] & 0x80 + mBlock := uint32(f.FISB_data[0] & 0x0f) << 16 + mBlock = mBlock | uint32(f.FISB_data[1]) << 8 + mBlock = mBlock | uint32(f.FISB_data[2]) + index := 3 + // Make 32 * 4 array + if elementIdentifier != 0 { + // Clear the array + for c:=0; c < (COLS_PER_BIN * ROWS_PER_BIN); c++ { + mData[c] = 0 + } + j := 0 + for index < int(f.FISB_length) { + numberOfBins := ((f.FISB_data[index] & 0xf8) >> 3) + 1 + for i:=0; i < int(numberOfBins); i++ { + if j >= int(COLS_PER_BIN*ROWS_PER_BIN) { + return + } + mData[j] = int32(f.FISB_data[index] & 0x07) + j++ + } + index++ + } + } else { + bitmapLen := int32(f.FISB_data[index] & 0x0f) + // Start with 1 element + + mEmpty[0] = int32(mBlock) + if (f.FISB_data[index] & 0x10) != 0 { + mEmpty = append(mEmpty, int32(mBlock+1)) + } + if (f.FISB_data[index] & 0x20) != 0 { + mEmpty = append(mEmpty, int32(mBlock+2)) + } + if (f.FISB_data[index] & 0x30) != 0 { + mEmpty = append(mEmpty, int32(mBlock+3)) + } + if (f.FISB_data[index] & 0x40) != 0 { + mEmpty = append(mEmpty, int32(mBlock+4)) + } + for i:=1; i