kopia lustrzana https://github.com/cyoung/stratux
commit
2d2d64a038
5
Makefile
5
Makefile
|
@ -1,7 +1,9 @@
|
|||
|
||||
ifeq "$(CIRCLECI)" "true"
|
||||
BUILDINFO=
|
||||
else
|
||||
BUILDINFO=-ldflags "-X main.stratuxVersion=`git describe --tags --abbrev=0` -X main.stratuxBuild=`git log -n 1 --pretty=%H`"
|
||||
$(if $(GOROOT),,$(error GOROOT is not set!))
|
||||
endif
|
||||
|
||||
all:
|
||||
|
@ -10,8 +12,9 @@ all:
|
|||
go get -t -d -v ./...
|
||||
go build $(BUILDINFO) main/gen_gdl90.go main/traffic.go main/ry835ai.go main/network.go main/managementinterface.go main/sdr.go main/uibroadcast.go
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
sh -c true
|
||||
make -C test
|
||||
|
||||
www:
|
||||
mkdir -p /var/www
|
||||
|
|
|
@ -12,6 +12,7 @@ Supported WiFi adapters:
|
|||
* Edimax EW-7811Un
|
||||
|
||||
Tested RTL-SDR:
|
||||
* NooElec NESDR Nano 2 (best)
|
||||
* NooElec NESDR Mini 2
|
||||
* Generic R820T (degraded performance)
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ apt-get install -y git cmake libusb-1.0-0.dev build-essential
|
|||
|
||||
cd /root
|
||||
rm -rf rtl-sdr
|
||||
git clone git://git.osmocom.org/rtl-sdr.git
|
||||
git clone https://github.com/jpoirier/librtlsdr rtl-sdr
|
||||
cd rtl-sdr
|
||||
mkdir build
|
||||
cd build
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/gzip"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
@ -23,16 +24,13 @@ import (
|
|||
|
||||
const (
|
||||
configLocation = "/etc/stratux.conf"
|
||||
indexFilename = "/var/log/stratux/LOGINDEX"
|
||||
managementAddr = ":80"
|
||||
debugLog = "/var/log/stratux.log"
|
||||
maxDatagramSize = 8192
|
||||
maxUserMsgQueueSize = 25000 // About 10MB per port per connected client.
|
||||
uatReplayLog = "/var/log/stratux-uat.log"
|
||||
esReplayLog = "/var/log/stratux-es.log"
|
||||
gpsReplayLog = "/var/log/stratux-gps.log"
|
||||
ahrsReplayLog = "/var/log/stratux-ahrs.log"
|
||||
dump1090ReplayLog = "/var/log/stratux-dump1090.log"
|
||||
|
||||
logDirectory = "/var/log/stratux"
|
||||
|
||||
UPLINK_BLOCK_DATA_BITS = 576
|
||||
UPLINK_BLOCK_BITS = (UPLINK_BLOCK_DATA_BITS + 160)
|
||||
UPLINK_BLOCK_DATA_BYTES = (UPLINK_BLOCK_DATA_BITS / 8)
|
||||
|
@ -62,6 +60,12 @@ const (
|
|||
TRACK_RESOLUTION = float32(360.0 / 256.0)
|
||||
)
|
||||
|
||||
var uatReplayLog string
|
||||
var esReplayLog string
|
||||
var gpsReplayLog string
|
||||
var ahrsReplayLog string
|
||||
var dump1090ReplayLog string
|
||||
|
||||
var stratuxBuild string
|
||||
var stratuxVersion string
|
||||
|
||||
|
@ -72,11 +76,11 @@ var Crc16Table [256]uint16
|
|||
var mySituation SituationData
|
||||
|
||||
// File handles for replay logging.
|
||||
var uatReplayfp *os.File
|
||||
var esReplayfp *os.File
|
||||
var gpsReplayfp *os.File
|
||||
var ahrsReplayfp *os.File
|
||||
var dump1090Replayfp *os.File
|
||||
var uatReplayWriter *gzip.Writer
|
||||
var esReplayWriter *gzip.Writer
|
||||
var gpsReplayWriter *gzip.Writer
|
||||
var ahrsReplayWriter *gzip.Writer
|
||||
var dump1090ReplayWriter *gzip.Writer
|
||||
|
||||
type msg struct {
|
||||
MessageClass uint
|
||||
|
@ -103,8 +107,49 @@ type ADSBTower struct {
|
|||
Messages_total uint64
|
||||
}
|
||||
|
||||
|
||||
var ADSBTowers map[string]ADSBTower // Running list of all towers seen. (lat,lng) -> ADSBTower
|
||||
|
||||
func constructFilenames() {
|
||||
// uatReplayLog = "/var/log/stratux-uat.log"
|
||||
// esReplayLog = "/var/log/stratux-es.log"
|
||||
// gpsReplayLog = "/var/log/stratux-gps.log"
|
||||
// ahrsReplayLog = "/var/log/stratux-ahrs.log"
|
||||
// dump1090ReplayLog = "/var/log/stratux-dump1090.log"
|
||||
var fileIndexNumber uint
|
||||
|
||||
// First, create the log file directory if it does not exist
|
||||
os.Mkdir(logDirectory,0644)
|
||||
|
||||
f, err := os.Open(indexFilename)
|
||||
if err != nil {
|
||||
log.Printf("Unable to open index file %s using index of 0\n", indexFilename)
|
||||
fileIndexNumber=0
|
||||
} else {
|
||||
_, err := fmt.Fscanf(f,"%d\n",&fileIndexNumber)
|
||||
if err != nil {
|
||||
log.Printf("Unable to read index file %s using index of 0\n", indexFilename)
|
||||
}
|
||||
f.Close()
|
||||
fileIndexNumber++
|
||||
}
|
||||
fo, err := os.Create(indexFilename)
|
||||
if err != nil {
|
||||
log.Printf("Error creating index file %s\n", indexFilename)
|
||||
}
|
||||
_, err2 := fmt.Fprintf(fo,"%d\n",fileIndexNumber)
|
||||
if err2 != nil {
|
||||
log.Printf("Error writing to index file %s\n", indexFilename)
|
||||
}
|
||||
fo.Sync()
|
||||
fo.Close()
|
||||
uatReplayLog = fmt.Sprintf("%s/%04d-uat.log.gz",logDirectory,fileIndexNumber)
|
||||
esReplayLog = fmt.Sprintf("%s/%04d-es.log.gz",logDirectory,fileIndexNumber)
|
||||
gpsReplayLog = fmt.Sprintf("%s/%04d-gps.log.gz",logDirectory,fileIndexNumber)
|
||||
ahrsReplayLog = fmt.Sprintf("%s/%04d-ahrs.log.gz",logDirectory,fileIndexNumber)
|
||||
dump1090ReplayLog = fmt.Sprintf("%s/%04d-dump1090.log.gz",logDirectory,fileIndexNumber)
|
||||
}
|
||||
|
||||
// Construct the CRC table. Adapted from FAA ref above.
|
||||
func crcInit() {
|
||||
var i uint16
|
||||
|
@ -506,22 +551,22 @@ func replayLog(msg string, msgclass int) {
|
|||
if len(msg) == 0 { // Blank message.
|
||||
return
|
||||
}
|
||||
var fp *os.File
|
||||
var wt *gzip.Writer
|
||||
switch msgclass {
|
||||
case MSGCLASS_UAT:
|
||||
fp = uatReplayfp
|
||||
wt = uatReplayWriter
|
||||
case MSGCLASS_ES:
|
||||
fp = esReplayfp
|
||||
wt = esReplayWriter
|
||||
case MSGCLASS_GPS:
|
||||
fp = gpsReplayfp
|
||||
wt = gpsReplayWriter
|
||||
case MSGCLASS_AHRS:
|
||||
fp = ahrsReplayfp
|
||||
wt = ahrsReplayWriter
|
||||
case MSGCLASS_DUMP1090:
|
||||
fp = dump1090Replayfp
|
||||
wt = dump1090ReplayWriter
|
||||
}
|
||||
if fp != nil {
|
||||
if wt != nil {
|
||||
s := makeReplayLogEntry(msg)
|
||||
fp.Write([]byte(s))
|
||||
wt.Write([]byte(s))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -816,37 +861,41 @@ func replayMark(active bool) {
|
|||
t = fmt.Sprintf("UNPAUSE,%d\n", time.Since(timeStarted).Nanoseconds())
|
||||
}
|
||||
|
||||
if uatReplayfp != nil {
|
||||
uatReplayfp.Write([]byte(t))
|
||||
if uatReplayWriter != nil {
|
||||
uatReplayWriter.Write([]byte(t))
|
||||
}
|
||||
|
||||
if esReplayfp != nil {
|
||||
esReplayfp.Write([]byte(t))
|
||||
if esReplayWriter != nil {
|
||||
esReplayWriter.Write([]byte(t))
|
||||
}
|
||||
|
||||
if gpsReplayfp != nil {
|
||||
gpsReplayfp.Write([]byte(t))
|
||||
if gpsReplayWriter != nil {
|
||||
gpsReplayWriter.Write([]byte(t))
|
||||
}
|
||||
|
||||
if ahrsReplayfp != nil {
|
||||
ahrsReplayfp.Write([]byte(t))
|
||||
if ahrsReplayWriter != nil {
|
||||
ahrsReplayWriter.Write([]byte(t))
|
||||
}
|
||||
|
||||
if dump1090Replayfp != nil {
|
||||
dump1090Replayfp.Write([]byte(t))
|
||||
if dump1090ReplayWriter != nil {
|
||||
dump1090ReplayWriter.Write([]byte(t))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func openReplay(fn string) (*os.File, error) {
|
||||
ret, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
func openReplay(fn string) (*gzip.Writer, error) {
|
||||
fp, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to open log file '%s': %s\n", fn, err.Error())
|
||||
} else {
|
||||
timeFmt := "Mon Jan 2 15:04:05 -0700 MST 2006"
|
||||
fmt.Fprintf(ret, "START,%s,%s\n", timeStarted.Format(timeFmt), time.Now().Format(timeFmt)) // Start time marker.
|
||||
return nil, err
|
||||
}
|
||||
return ret, err
|
||||
|
||||
gzw := gzip.NewWriter(fp) //FIXME: Close() on the gzip.Writer will not close the underlying file.
|
||||
timeFmt := "Mon Jan 2 15:04:05 -0700 MST 2006"
|
||||
s := fmt.Sprintf("START,%s,%s\n", timeStarted.Format(timeFmt), time.Now().Format(timeFmt)) // Start time marker.
|
||||
gzw.Write([]byte(s))
|
||||
return gzw, err
|
||||
}
|
||||
|
||||
func printStats() {
|
||||
|
@ -879,7 +928,8 @@ func main() {
|
|||
}
|
||||
|
||||
log.Printf("Stratux %s (%s) starting.\n", stratuxVersion, stratuxBuild)
|
||||
|
||||
constructFilenames()
|
||||
|
||||
ADSBTowers = make(map[string]ADSBTower)
|
||||
MsgLog = make([]msg, 0)
|
||||
|
||||
|
@ -894,39 +944,39 @@ func main() {
|
|||
// Set up the replay logs. Keep these files open in any case, even if replay logging is disabled.
|
||||
|
||||
// UAT replay log.
|
||||
if uatfp, err := openReplay(uatReplayLog); err != nil {
|
||||
if uatwt, err := openReplay(uatReplayLog); err != nil {
|
||||
globalSettings.ReplayLog = false
|
||||
} else {
|
||||
uatReplayfp = uatfp
|
||||
defer uatReplayfp.Close()
|
||||
uatReplayWriter = uatwt
|
||||
defer uatReplayWriter.Close()
|
||||
}
|
||||
// 1090ES replay log.
|
||||
if esfp, err := openReplay(esReplayLog); err != nil {
|
||||
if eswt, err := openReplay(esReplayLog); err != nil {
|
||||
globalSettings.ReplayLog = false
|
||||
} else {
|
||||
esReplayfp = esfp
|
||||
defer esReplayfp.Close()
|
||||
esReplayWriter = eswt
|
||||
defer esReplayWriter.Close()
|
||||
}
|
||||
// GPS replay log.
|
||||
if gpsfp, err := openReplay(gpsReplayLog); err != nil {
|
||||
if gpswt, err := openReplay(gpsReplayLog); err != nil {
|
||||
globalSettings.ReplayLog = false
|
||||
} else {
|
||||
gpsReplayfp = gpsfp
|
||||
defer gpsReplayfp.Close()
|
||||
gpsReplayWriter = gpswt
|
||||
defer gpsReplayWriter.Close()
|
||||
}
|
||||
// AHRS replay log.
|
||||
if ahrsfp, err := openReplay(ahrsReplayLog); err != nil {
|
||||
if ahrswt, err := openReplay(ahrsReplayLog); err != nil {
|
||||
globalSettings.ReplayLog = false
|
||||
} else {
|
||||
ahrsReplayfp = ahrsfp
|
||||
defer ahrsReplayfp.Close()
|
||||
ahrsReplayWriter = ahrswt
|
||||
defer ahrsReplayWriter.Close()
|
||||
}
|
||||
// Dump1090 replay log.
|
||||
if dump1090fp, err := openReplay(dump1090ReplayLog); err != nil {
|
||||
if dump1090wt, err := openReplay(dump1090ReplayLog); err != nil {
|
||||
globalSettings.ReplayLog = false
|
||||
} else {
|
||||
dump1090Replayfp = dump1090fp
|
||||
defer dump1090Replayfp.Close()
|
||||
dump1090ReplayWriter = dump1090wt
|
||||
defer dump1090ReplayWriter.Close()
|
||||
}
|
||||
|
||||
// Mark the files (whether we're logging or not).
|
||||
|
|
|
@ -101,6 +101,21 @@ func handleStatusWS(conn *websocket.Conn) {
|
|||
}
|
||||
}
|
||||
|
||||
func handleSituationWS(conn *websocket.Conn) {
|
||||
timer := time.NewTicker(100 * time.Millisecond)
|
||||
for {
|
||||
<-timer.C
|
||||
situationJSON, _ := json.Marshal(&mySituation)
|
||||
_, err := conn.Write(situationJSON)
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// AJAX call - /getStatus. Responds with current global status
|
||||
// a webservice call for the same data available on the websocket but when only a single update is needed
|
||||
func handleStatusRequest(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -225,6 +240,12 @@ func managementInterface() {
|
|||
Handler: websocket.Handler(handleStatusWS)}
|
||||
s.ServeHTTP(w, req)
|
||||
})
|
||||
http.HandleFunc("/situation",
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
s := websocket.Server{
|
||||
Handler: websocket.Handler(handleSituationWS)}
|
||||
s.ServeHTTP(w, req)
|
||||
})
|
||||
http.HandleFunc("/weather",
|
||||
func(w http.ResponseWriter, req *http.Request) {
|
||||
s := websocket.Server{
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
ifeq "$(CIRCLECI)" "true"
|
||||
#
|
||||
else
|
||||
$(if $(GOROOT),,$(error GOROOT is not set!))
|
||||
endif
|
||||
|
||||
SRCS = $(wildcard *.go)
|
||||
DEST = $(patsubst %.go,%,$(SRCS))
|
||||
|
||||
all: $(DEST)
|
||||
|
||||
%: %.go
|
||||
go build $<
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kidoman/embd"
|
||||
_ "github.com/kidoman/embd/host/all"
|
||||
"github.com/kidoman/embd/sensor/bmp180"
|
||||
)
|
||||
|
||||
|
||||
var i2cbus embd.I2CBus
|
||||
var myBMP180 *bmp180.BMP180
|
||||
|
||||
func readBMP180() (float64, float64, error) { // ºCelsius, Meters
|
||||
temp, err := myBMP180.Temperature()
|
||||
if err != nil {
|
||||
return temp, 0.0, err
|
||||
}
|
||||
altitude, err := myBMP180.Altitude()
|
||||
altitude = float64(1/0.3048) * altitude // Convert meters to feet.
|
||||
if err != nil {
|
||||
return temp, altitude, err
|
||||
}
|
||||
return temp, altitude, nil
|
||||
}
|
||||
|
||||
|
||||
func initBMP180() error {
|
||||
myBMP180 = bmp180.New(i2cbus) //TODO: error checking.
|
||||
return nil
|
||||
}
|
||||
|
||||
func initI2C() error {
|
||||
i2cbus = embd.NewI2CBus(1) //TODO: error checking.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unused at the moment. 5 second update, since read functions in bmp180 are slow.
|
||||
func tempAndPressureReader() {
|
||||
// Read temperature and pressure altitude.
|
||||
temp, alt, err_bmp180 := readBMP180()
|
||||
// Process.
|
||||
if err_bmp180 != nil {
|
||||
fmt.Printf("readBMP180(): %s\n", err_bmp180.Error())
|
||||
} else {
|
||||
fmt.Printf("Temp %f Alt %f\n",temp,alt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func initAHRS() error {
|
||||
if err := initI2C(); err != nil { // I2C bus.
|
||||
return err
|
||||
}
|
||||
if err := initBMP180(); err != nil { // I2C temperature and pressure altitude.
|
||||
i2cbus.Close()
|
||||
return err
|
||||
}
|
||||
go tempAndPressureReader()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Hello world!\n")
|
||||
initAHRS()
|
||||
for {
|
||||
tempAndPressureReader()
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue