Merge pull request #1 from cyoung/master

Merge upstream
pull/11/head
Brant K. Kyser 2015-08-20 12:33:02 -05:00
commit 1437a07f7a
6 zmienionych plików z 275 dodań i 211 usunięć

Wyświetl plik

@ -1,133 +0,0 @@
package main
import (
"bufio"
"fmt"
"net"
"strconv"
"strings"
"sync"
"time"
)
const (
ipadAddr = "192.168.10.255:49002"
dump1090Addr = "127.0.0.1:30003"
maxDatagramSize = 8192
)
type PositionInfo struct {
lat string
lng string
alt string
hdg string
vel string
vr string
tail string
last_seen time.Time
}
func cleanupOldEntries() {
for icaoDec, pi := range blips {
s := time.Since(pi.last_seen)
if s.Seconds() >= float64(15) { // Timeout time.
//log.Printf("REMOVED %d\n", icaoDec)
delete(blips, icaoDec)
}
}
}
func ipadUpdate(mutex *sync.Mutex) {
addr, err := net.ResolveUDPAddr("udp", ipadAddr)
if err != nil {
panic(err)
}
outConn, err := net.DialUDP("udp", nil, addr)
for {
mutex.Lock()
cleanupOldEntries()
for icaoDec, pi := range blips {
msg := fmt.Sprintf("XTRAFFICMy Sim,%d,%s,%s,%s,%s,1,%s,%s,%s", icaoDec, pi.lat, pi.lng, pi.alt, pi.vr, pi.hdg, pi.vel, pi.tail)
//log.Println(msg)
outConn.Write([]byte(msg))
}
mutex.Unlock()
time.Sleep(1 * time.Second)
}
// c.Write([]byte("XTRAFFICMy Sim,168,42.503464,-83.622551,3749.9,-213.0,1,68.2,126.0,KS6"))
}
var blips map[int64]PositionInfo
func main() {
mutex := &sync.Mutex{}
blips = make(map[int64]PositionInfo)
go ipadUpdate(mutex)
for {
inConn, err := net.Dial("tcp", dump1090Addr)
if err != nil {
time.Sleep(1 * time.Second)
continue
}
rdr := bufio.NewReader(inConn)
for {
buf, err := rdr.ReadString('\n')
if err != nil { // Must have disconnected?
break
}
buf = strings.Trim(buf, "\r\n")
//log.Printf("%s\n", buf)
x := strings.Split(buf, ",")
//TODO: Add more sophisticated stuff that combines heading/speed updates with the location.
if len(x) < 22 {
continue
}
icao := x[4]
icaoDec, err := strconv.ParseInt(icao, 16, 32)
if err != nil {
continue
}
mutex.Lock()
// Retrieve previous information on this ICAO code.
var pi PositionInfo
if _, ok := blips[icaoDec]; ok {
pi = blips[icaoDec]
}
if x[1] == "3" {
//MSG,3,111,11111,AC2BB7,111111,2015/07/28,03:59:12.363,2015/07/28,03:59:12.353,,5550,,,42.35847,-83.42212,,,,,,0
alt := x[11]
lat := x[14]
lng := x[15]
//log.Printf("icao=%s, icaoDec=%d, alt=%s, lat=%s, lng=%s\n", icao, icaoDec, alt, lat, lng)
pi.alt = alt
pi.lat = lat
pi.lng = lng
}
if x[1] == "4" {
// MSG,4,111,11111,A3B557,111111,2015/07/28,06:13:36.417,2015/07/28,06:13:36.398,,,414,278,,,-64,,,,,0
vel := x[12]
hdg := x[13]
vr := x[16]
//log.Printf("icao=%s, icaoDec=%d, vel=%s, hdg=%s, vr=%s\n", icao, icaoDec, vel, hdg, vr)
pi.vel = vel
pi.hdg = hdg
pi.vr = vr
}
if x[1] == "1" {
// MSG,1,,,%02X%02X%02X,,,,,,%s,,,,,,,,0,0,0,0
tail := x[10]
pi.tail = tail
}
// Update "last seen" (any type of message).
pi.last_seen = time.Now()
blips[icaoDec] = pi // Update information on this ICAO code.
mutex.Unlock()
}
}
}

Wyświetl plik

@ -1,4 +1,4 @@
all:
GOARCH=6 go-linux-arm build gen_gdl90.go traffic.go ry835ai.go
GOOS=linux GOARCH=arm GOARM=6 go build gen_gdl90.go traffic.go ry835ai.go network.go
clean:
rm -f gen_gdl90

Wyświetl plik

@ -11,3 +11,7 @@ Supported WiFi adapters:
Tested RTL-SDR:
*NooElec NESDR Mini 2
https://www.reddit.com/r/stratux

Wyświetl plik

@ -17,6 +17,7 @@ import (
const (
stratuxVersion = "v0.1"
configLocation = "/etc/stratux.conf"
managementAddr = "127.0.0.1:9110"
maxDatagramSize = 8192
UPLINK_BLOCK_DATA_BITS = 576
UPLINK_BLOCK_BITS = (UPLINK_BLOCK_DATA_BITS + 160)
@ -45,7 +46,6 @@ const (
)
var Crc16Table [256]uint16
var outConn *net.UDPConn
var myGPS GPSData
@ -197,7 +197,7 @@ func makeOwnshipReport() bool {
msg[18] = 0x01 // "Light (ICAO) < 15,500 lbs"
outConn.Write(prepareMessage(msg))
sendMsg(prepareMessage(msg))
return true
}
@ -218,7 +218,7 @@ func makeOwnshipGeometricAltitudeReport() bool {
msg[3] = 0x00
msg[4] = 0x0A
outConn.Write(prepareMessage(msg))
sendMsg(prepareMessage(msg))
return true
}
@ -265,19 +265,20 @@ func relayMessage(msgtype uint16, msg []byte) {
ret[i+4] = msg[i]
}
outConn.Write(prepareMessage(ret))
sendMsg(prepareMessage(ret))
}
func heartBeatSender() {
timer := time.Tick(1 * time.Second)
for {
outConn.Write(makeHeartbeat())
// outConn.Write(makeTrafficReport())
<-timer
sendMsg(makeHeartbeat())
// sendMsg(makeTrafficReport())
makeOwnshipReport()
makeOwnshipGeometricAltitudeReport()
outConn.Write(makeInitializationMessage())
sendMsg(makeInitializationMessage())
sendTrafficUpdates()
updateStatus()
time.Sleep(1 * time.Second)
}
}
@ -358,7 +359,7 @@ type settings struct {
UAT_Enabled bool
ES_Enabled bool
GPS_Enabled bool
IpadAddr string
GDLOutputPorts []uint16
}
type status struct {
@ -411,7 +412,7 @@ func handleManagementConnection(conn net.Conn) {
}
func managementInterface() {
ln, err := net.Listen("tcp", "127.0.0.1:9110")
ln, err := net.Listen("tcp", managementAddr)
if err != nil { //TODO
log.Printf("couldn't open management port: %s\n", err.Error())
return
@ -430,7 +431,7 @@ func defaultSettings() {
globalSettings.UAT_Enabled = true //TODO
globalSettings.ES_Enabled = false //TODO
globalSettings.GPS_Enabled = false //TODO
globalSettings.IpadAddr = "192.168.10.255:4000" // Port 4000 for FreeFlight RANGR.
globalSettings.GDLOutputPorts = []uint16{4000, 43211}
}
func readSettings() {
@ -489,21 +490,16 @@ func main() {
go gpsReader()
}
// Open UDP port to send out the messages.
addr, err := net.ResolveUDPAddr("udp", globalSettings.IpadAddr)
if err != nil {
panic(err)
}
outConn, err = net.DialUDP("udp", nil, addr)
if err != nil {
panic("error creating UDP socket: " + err.Error())
}
//TODO: network stuff
// Start the heartbeat message loop in the background, once per second.
go heartBeatSender()
// Start the management interface.
go managementInterface()
// Initialize the (out) network handler.
initNetwork()
reader := bufio.NewReader(os.Stdin)
for {

123
network.go 100644
Wyświetl plik

@ -0,0 +1,123 @@
package main
import (
"io/ioutil"
"log"
"net"
"strconv"
"strings"
"sync"
"time"
)
var messageQueue chan []byte
var outSockets map[string]*net.UDPConn
var dhcpLeases map[string]string
var netMutex *sync.Mutex
// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
dat, err := ioutil.ReadFile("/var/lib/dhcp/dhcpd.leases")
ret := make(map[string]string)
if err != nil {
return ret, err
}
lines := strings.Split(string(dat), "\n")
open_block := false
block_ip := ""
for _, line := range lines {
spaced := strings.Split(line, " ")
if len(spaced) > 2 && spaced[0] == "lease" {
open_block = true
block_ip = spaced[1]
} else if open_block && len(spaced) >= 4 && spaced[2] == "client-hostname" {
hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
ret[block_ip] = hostname
open_block = false
}
}
return ret, nil
}
func sendToAllConnectedClients(msg []byte) {
netMutex.Lock()
defer netMutex.Unlock()
for _, sock := range outSockets {
sock.Write(msg)
}
}
// Just returns the number of DHCP leases for now.
func getNetworkStats() int {
return len(dhcpLeases)
}
// See who has a DHCP lease and make a UDP connection to each of them.
func refreshConnectedClients() {
netMutex.Lock()
defer netMutex.Unlock()
validConnections := make(map[string]bool)
t, err := getDHCPLeases()
if err != nil {
log.Printf("getDHCPLeases(): %s\n", err.Error())
return
}
dhcpLeases = t
// Client connected that wasn't before.
for ip, hostname := range dhcpLeases {
for _, port := range globalSettings.GDLOutputPorts {
ipAndPort := ip + ":" + strconv.Itoa(int(port))
if _, ok := outSockets[ipAndPort]; !ok {
log.Printf("client connected: %s:%d (%s).\n", ip, port, hostname)
addr, err := net.ResolveUDPAddr("udp", ipAndPort)
if err != nil {
log.Printf("ResolveUDPAddr(%s): %s\n", ipAndPort, err.Error())
continue
}
outConn, err := net.DialUDP("udp", nil, addr)
if err != nil {
log.Printf("DialUDP(%s): %s\n", ipAndPort, err.Error())
continue
}
outSockets[ipAndPort] = outConn
}
validConnections[ipAndPort] = true
}
}
// Client that was connected before that isn't.
for ipAndPort, conn := range outSockets {
if _, ok := validConnections[ipAndPort]; !ok {
log.Printf("removed connection %s.\n", ipAndPort)
conn.Close()
delete(outSockets, ipAndPort)
}
}
}
func messageQueueSender() {
secondTimer := time.NewTicker(1 * time.Second)
dhcpRefresh := time.NewTicker(30 * time.Second)
for {
select {
case msg := <-messageQueue:
sendToAllConnectedClients(msg)
case <-secondTimer.C:
getNetworkStats()
case <-dhcpRefresh.C:
refreshConnectedClients()
}
}
}
func sendMsg(msg []byte) {
messageQueue <- msg
}
func initNetwork() {
messageQueue = make(chan []byte, 1024) // Buffered channel, 1024 messages.
outSockets = make(map[string]*net.UDPConn)
netMutex = &sync.Mutex{}
refreshConnectedClients()
go messageQueueSender()
}

Wyświetl plik

@ -3,12 +3,12 @@ package main
import (
"encoding/hex"
"math"
"sync"
"time"
)
//-0b2b48fe3aef1f88621a0856110a31c01105c4e6c4e6c40a9a820300000000000000;rs=7;
/*
HDR:
@ -67,8 +67,11 @@ type TrafficInfo struct {
}
var traffic map[uint32]TrafficInfo
var trafficMutex *sync.Mutex
func cleanupOldEntries() {
trafficMutex.Lock()
defer trafficMutex.Unlock()
for icao_addr, ti := range traffic {
if time.Since(ti.last_seen).Seconds() > float64(60) { //FIXME: 60 seconds with no update on this address - stop displaying.
delete(traffic, icao_addr)
@ -77,6 +80,8 @@ func cleanupOldEntries() {
}
func sendTrafficUpdates() {
trafficMutex.Lock()
defer trafficMutex.Unlock()
cleanupOldEntries()
for _, ti := range traffic {
makeTrafficReport(ti)
@ -85,6 +90,7 @@ func sendTrafficUpdates() {
func initTraffic() {
traffic = make(map[uint32]TrafficInfo)
trafficMutex = &sync.Mutex{}
}
func makeTrafficReport(ti TrafficInfo) {
@ -113,7 +119,6 @@ func makeTrafficReport(ti TrafficInfo) {
msg[9] = tmp[1] // Longitude.
msg[10] = tmp[2] // Longitude.
//Altitude: OK
//TODO: 0xFFF "invalid altitude."
alt := uint16(ti.alt)
@ -143,10 +148,9 @@ func makeTrafficReport(ti TrafficInfo) {
msg[18] = 0x01 // "light"
outConn.Write(prepareMessage(msg))
sendMsg(prepareMessage(msg))
}
func parseDownlinkReport(s string) {
var ti TrafficInfo
s = s[1:]
@ -282,5 +286,75 @@ func parseDownlinkReport(s string) {
ti.last_seen = time.Now()
trafficMutex.Lock()
traffic[ti.icao_addr] = ti
trafficMutex.Unlock()
}
//TODO
/*
// dump1090Addr = "127.0.0.1:30003"
inConn, err := net.Dial("tcp", dump1090Addr)
if err != nil {
time.Sleep(1 * time.Second)
continue
}
rdr := bufio.NewReader(inConn)
for {
buf, err := rdr.ReadString('\n')
if err != nil { // Must have disconnected?
break
}
buf = strings.Trim(buf, "\r\n")
//log.Printf("%s\n", buf)
x := strings.Split(buf, ",")
//TODO: Add more sophisticated stuff that combines heading/speed updates with the location.
if len(x) < 22 {
continue
}
icao := x[4]
icaoDec, err := strconv.ParseInt(icao, 16, 32)
if err != nil {
continue
}
mutex.Lock()
// Retrieve previous information on this ICAO code.
var pi PositionInfo
if _, ok := blips[icaoDec]; ok {
pi = blips[icaoDec]
}
if x[1] == "3" {
//MSG,3,111,11111,AC2BB7,111111,2015/07/28,03:59:12.363,2015/07/28,03:59:12.353,,5550,,,42.35847,-83.42212,,,,,,0
alt := x[11]
lat := x[14]
lng := x[15]
//log.Printf("icao=%s, icaoDec=%d, alt=%s, lat=%s, lng=%s\n", icao, icaoDec, alt, lat, lng)
pi.alt = alt
pi.lat = lat
pi.lng = lng
}
if x[1] == "4" {
// MSG,4,111,11111,A3B557,111111,2015/07/28,06:13:36.417,2015/07/28,06:13:36.398,,,414,278,,,-64,,,,,0
vel := x[12]
hdg := x[13]
vr := x[16]
//log.Printf("icao=%s, icaoDec=%d, vel=%s, hdg=%s, vr=%s\n", icao, icaoDec, vel, hdg, vr)
pi.vel = vel
pi.hdg = hdg
pi.vr = vr
}
if x[1] == "1" {
// MSG,1,,,%02X%02X%02X,,,,,,%s,,,,,,,,0,0,0,0
tail := x[10]
pi.tail = tail
}
// Update "last seen" (any type of message).
pi.last_seen = time.Now()
blips[icaoDec] = pi // Update information on this ICAO code.
mutex.Unlock()
*/