Initial support for NEXRAD data, added support for JSON types

pull/515/head
Jim Jacobsen 2016-10-23 23:38:13 -05:00
rodzic 92e48862e2
commit 7239e81418
4 zmienionych plików z 187 dodań i 9 usunięć

Wyświetl plik

@ -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
}

36
main/managementinterface.go 100644 → 100755
Wyświetl plik

@ -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)

1
main/traffic.go 100644 → 100755
Wyświetl plik

@ -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.

126
uatparse/uatparse.go 100644 → 100755
Wyświetl plik

@ -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<int(bitmapLen); i++ {
if (f.FISB_data[index+i] & 0x01) != 0 {
mEmpty = append(mEmpty, int32(mBlock + uint32(i) * 8 - 3))
}
if (f.FISB_data[index+i] & 0x02) != 0 {
mEmpty = append(mEmpty, int32(mBlock + uint32(i) * 8 - 2))
}
if (f.FISB_data[index+i] & 0x04) != 0 {
mEmpty = append(mEmpty, int32(mBlock + uint32(i) * 8 - 1))
}
if (f.FISB_data[index+i] & 0x08) != 0 {
mEmpty = append(mEmpty, int32( mBlock + uint32(i) * 8 - 0))
}
if (f.FISB_data[index+i] & 0x10) != 0 {
mEmpty = append(mEmpty, int32(mBlock + uint32(i) * 8 + 1))
}
if (f.FISB_data[index+i] & 0x20) != 0 {
mEmpty = append(mEmpty, int32(mBlock + uint32(i) * 8 + 2))
}
if (f.FISB_data[index+i] & 0x40) != 0 {
mEmpty = append(mEmpty, int32(mBlock + uint32(i) * 8 + 3))
}
if (f.FISB_data[index+i] & 0x80) != 0 {
mEmpty = append(mEmpty, int32(mBlock + uint32(i) * 8 + 4))
}
}
}
log.Printf("NEXRAD: elementIdentifier %d mBlock %d\n",elementIdentifier, mBlock)
log.Printf("NEXRAD: mEmpty %d mData %d\n",mEmpty, mData)
// field 1 - NEXRAD
builder = append(builder,"NEXRAD")
// CONUS
if f.Product_id == 63 {
builder = append(builder,"0")
} else {
builder = append(builder,"1")
}
// Field 3 block
builder = append(builder,fmt.Sprintf("%d",mBlock))
// Field 4 Columns
builder = append(builder,fmt.Sprintf("%d",COLS_PER_BIN))
// Field 5 Rows
builder = append(builder,fmt.Sprintf("%d",ROWS_PER_BIN))
if elementIdentifier != 0 {
builder = append(builder,"1")
bin := ""
for br := range mData {
bin = bin + fmt.Sprintf("%d,",mData[br])
}
if bin[len(bin)-1] == ',' {
bin = bin[0:len(bin)-1]
}
builder = append(builder,bin)
} else {
builder = append(builder,"0")
bin2 := ""
for be := range mEmpty {
bin2 = bin2 + fmt.Sprintf("%d,",mEmpty[be])
}
if bin2[len(bin2)-1] == ',' {
bin2 = bin2[0:len(bin2)-1]
}
builder = append(builder,bin2)
}
ret = append(ret, fmt.Sprintf(strings.Join(builder, " ")))
f.Text_data = ret
}
// Whole frame contents is DLAC encoded text.
func (f *UATFrame) decodeTextFrame() {
if len(f.FISB_data) < int(f.FISB_length) {
@ -500,6 +621,9 @@ func (f *UATFrame) decodeInfoFrame() {
case 8, 11, 13:
f.decodeAirmet()
*/
case 63, 64:
f.decodeNexradFrame()
default:
fmt.Fprintf(ioutil.Discard, "don't know what to do with product id: %d\n", f.Product_id)
}