diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/.DS_Store differ diff --git a/Makefile b/Makefile index 3d1b9ae0..79b10f5a 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ all: xgen_gdl90: go get -t -d -v ./main ./godump978 ./uatparse ./sensors - go build $(BUILDINFO) -p 4 main/gen_gdl90.go main/traffic.go main/gps.go main/network.go main/managementinterface.go main/sdr.go main/ping.go main/uibroadcast.go main/monotonic.go main/datalog.go main/equations.go main/sensors.go main/cputemp.go + go build $(BUILDINFO) -p 4 main/gen_gdl90.go main/traffic.go main/gps.go main/network.go main/managementinterface.go main/sdr.go main/ping.go main/uibroadcast.go main/monotonic.go main/datalog.go main/equations.go main/sensors.go main/cputemp.go main/lowpower_uat.go fancontrol: go get -t -d -v ./main diff --git a/image/10-stratux.rules b/image/10-stratux.rules index 22dec67c..4c815b12 100644 --- a/image/10-stratux.rules +++ b/image/10-stratux.rules @@ -12,6 +12,10 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a6", SYMLINK+=" #SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a7", SYMLINK+="vk172" #SUBSYSTEMS=="usb", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a6", SYMLINK+="vk162" +# Stratux uatradio. +# 0403:7028 (Stratux UATRadio) +ATTRS{idProduct}=="7028", ATTRS{idVendor}=="0403", RUN+="/sbin/modprobe -q ftdi_sio" RUN+="/bin/sh -c 'echo 0403 7028 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'", OWNER="root", MODE="0666", SYMLINK+="uatradio" + # pl2303 devices are indistinguishable using idVendor and idProduct. diff --git a/main/gen_gdl90.go b/main/gen_gdl90.go index 58584575..e77773dc 100644 --- a/main/gen_gdl90.go +++ b/main/gen_gdl90.go @@ -1132,6 +1132,7 @@ type status struct { UAT_traffic_targets_tracking uint16 ES_traffic_targets_tracking uint16 Ping_connected bool + UATRadio_connected bool GPS_satellites_locked uint16 GPS_satellites_seen uint16 GPS_satellites_tracked uint16 @@ -1573,6 +1574,9 @@ func main() { globalStatus.CPUTemp = cpuTemp }) + // Start reading from serial UAT radio. + initUATRadioSerial() + reader := bufio.NewReader(os.Stdin) if *replayFlag == true { diff --git a/main/lowpower_uat.go b/main/lowpower_uat.go new file mode 100644 index 00000000..321cbe52 --- /dev/null +++ b/main/lowpower_uat.go @@ -0,0 +1,155 @@ +package main + +import ( + "encoding/hex" + "fmt" + "github.com/stratux/serial" + "log" + "os" + "time" + "unsafe" +) + +/* + +#cgo LDFLAGS: -ldump978 + +#include +#include "../dump978/fec.h" + +*/ +import "C" + +var radioSerialConfig *serial.Config +var radioSerialPort *serial.Port + +func initUATRadioSerial() error { + // Init for FEC routines. + C.init_fec() + go func() { + watchTicker := time.NewTicker(1 * time.Second) + for { + <-watchTicker.C + // Watch for the radio or change in settings. + if !globalSettings.UAT_Enabled || globalStatus.UATRadio_connected { + // UAT not enabled or radio already set up. Continue. + continue + } + if _, err := os.Stat("/dev/uatradio"); err != nil { + // Device not connected. + continue + } + log.Printf("===== UAT Device Name : UATRadio v1.0 =====\n") + + // Initialize port at 2Mbaud. + radioSerialConfig = &serial.Config{Name: "/dev/uatradio", Baud: 2000000} + p, err := serial.OpenPort(radioSerialConfig) + if err != nil { + log.Printf("\tUAT Open Failed: %s\n", err.Error()) + continue + } + + log.Printf("\tUATRadio init success.\n") + + radioSerialPort = p + globalStatus.UATRadio_connected = true + + // Start a goroutine to watch the serial port. + go radioSerialPortReader(radioSerialPort) + } + }() + return nil +} + +/* + radioSerialPortReader(). + Loop to read data from the radio serial port. +*/ +var radioMagic = []byte{0x0a, 0xb0, 0xcd, 0xe0} + +func radioSerialPortReader(serialPort *serial.Port) { + defer func() { + globalStatus.UATRadio_connected = false + serialPort.Close() + }() + tmpBuf := make([]byte, 1024) // Read buffer. + var buf []byte // Message buffer. + for { + n, err := serialPort.Read(tmpBuf) + if err != nil { + log.Printf("serial port err, shutting down radio: %s\n", err.Error()) + return + } + buf = append(buf, tmpBuf[:n]...) + bufLen := len(buf) + var finBuf []byte // Truncated buffer, with processed messages extracted. + var numMessages int // Number of messages extracted. + // Search for a suitable message to extract. + for i := 0; i < bufLen-6; i++ { + if (buf[i] == radioMagic[0]) && (buf[i+1] == radioMagic[1]) && (buf[i+2] == radioMagic[2]) && (buf[i+3] == radioMagic[3]) { + // Found the magic sequence. Get the length. + msgLen := int(uint16(buf[i+4])+(uint16(buf[i+5])<<8)) + 5 // 5 bytes for RSSI and TS. + // Check if we've read enough to finish this message. + if bufLen < i+6+msgLen { + break // Wait for more of the message to come in. + } + // Message is long enough. + processRadioMessage(buf[i+6 : i+6+msgLen]) + // Remove everything in the buffer before this message. + finBuf = buf[i+6+msgLen:] + numMessages++ + } + } + if numMessages > 0 { + buf = finBuf + } + } +} + +/* + processRadioMessage(). + Processes a single message from the radio. De-interleaves (when necessary), checks Reed-Solomon, passes to main process. +*/ + +func processRadioMessage(msg []byte) { + // RSSI and message timestamp are prepended to the actual packet. + + // RSSI + rssiRaw := int8(msg[0]) + //rssiAdjusted := int16(rssiRaw) - 132 // -132 dBm, calculated minimum RSSI. + //rssiDump978 := int16(1000 * (10 ^ (float64(rssiAdjusted) / 20))) + rssiDump978 := rssiRaw + + //_ := uint32(msg[1]) + (uint32(msg[2]) << 8) + (uint32(msg[3]) << 16) + (uint32(msg[4]) << 24) // Timestamp. Currently unused. + + msg = msg[5:] + + var toRelay string + var rs_errors int + switch len(msg) { + case 552: + to := make([]byte, 552) + C.correct_uplink_frame((*C.uint8_t)(unsafe.Pointer(&msg[0])), (*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))) + toRelay = fmt.Sprintf("+%s;ss=%d;", hex.EncodeToString(to[:432]), rssiDump978) + case 48: + to := make([]byte, 48) + copy(to, msg) + i := int(C.correct_adsb_frame((*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors)))) + if i == 1 { + // Short ADS-B frame. + toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:18]), rssiDump978) + } else if i == 2 { + // Long ADS-B frame. + toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:34]), rssiDump978) + } + default: + log.Printf("processRadioMessage(): unhandled message size %d\n", len(msg)) + } + + if len(toRelay) > 0 && rs_errors != 9999 { + o, msgtype := parseInput(toRelay) + if o != nil && msgtype != 0 { + relayMessage(msgtype, o) + } + } +} diff --git a/main/sdr.go b/main/sdr.go index 40fab42f..596e9974 100644 --- a/main/sdr.go +++ b/main/sdr.go @@ -522,7 +522,11 @@ func sdrWatcher() { esEnabled := globalSettings.ES_Enabled uatEnabled := globalSettings.UAT_Enabled count := rtl.GetDeviceCount() - atomic.StoreUint32(&globalStatus.Devices, uint32(count)) + interfaceCount := count + if globalStatus.UATRadio_connected { + interfaceCount++ + } + atomic.StoreUint32(&globalStatus.Devices, uint32(interfaceCount)) // support up to two dongles if count > 2 {