More data logger boilerplate. Add to Makefile and init in main().

pull/406/head
Christopher Young 2016-03-24 09:33:11 -04:00
rodzic 67d62184d3
commit 854b96f608
3 zmienionych plików z 63 dodań i 60 usunięć

Wyświetl plik

@ -14,7 +14,7 @@ all:
xgen_gdl90: xgen_gdl90:
go get -t -d -v ./main ./test ./linux-mpu9150/mpu ./godump978 ./mpu6050 ./uatparse go get -t -d -v ./main ./test ./linux-mpu9150/mpu ./godump978 ./mpu6050 ./uatparse
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 main/monotonic.go 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 main/monotonic.go main/datalog.go
xdump1090: xdump1090:
git submodule update --init git submodule update --init

Wyświetl plik

@ -14,6 +14,8 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"log"
"os"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
@ -21,7 +23,7 @@ import (
) )
const ( const (
LOG_TIMESTAMP_RESOLUTION = 50 * time.Millisecond LOG_TIMESTAMP_RESOLUTION = 250 * time.Millisecond
) )
type StratuxTimestamp struct { type StratuxTimestamp struct {
@ -45,8 +47,10 @@ func checkTimestamp() bool {
if time.Since(dataLogTimestamp.StratuxClock_value) >= LOG_TIMESTAMP_RESOLUTION { if time.Since(dataLogTimestamp.StratuxClock_value) >= LOG_TIMESTAMP_RESOLUTION {
//FIXME: mutex. //FIXME: mutex.
dataLogTimestamp.id = 0 dataLogTimestamp.id = 0
dataLogTimestamp.StratuxClock_value = time.Now() dataLogTimestamp.Time_type_preference = 0 // stratuxClock.
dataLogTimestamp.Time_type_preference = 0 dataLogTimestamp.StratuxClock_value = stratuxClock.Time
dataLogTimestamp.GPSClock_value = time.Time{}
dataLogTimestamp.PreferredTime_value = stratuxClock.Time
return false return false
} }
@ -66,14 +70,6 @@ func boolMarshal(v reflect.Value) string {
return "0" return "0"
} }
func structCanBeMarshalled(v reflect.Value) bool {
m := v.MethodByName("String")
if m.IsValid() && !m.IsNil() {
return true
}
return false
}
func intMarshal(v reflect.Value) string { func intMarshal(v reflect.Value) string {
return strconv.FormatInt(v.Int(), 10) return strconv.FormatInt(v.Int(), 10)
} }
@ -94,6 +90,14 @@ func notsupportedMarshal(v reflect.Value) string {
return "" return ""
} }
func structCanBeMarshalled(v reflect.Value) bool {
m := v.MethodByName("String")
if m.IsValid() && !m.IsNil() {
return true
}
return false
}
func structMarshal(v reflect.Value) string { func structMarshal(v reflect.Value) string {
if structCanBeMarshalled(v) { if structCanBeMarshalled(v) {
m := v.MethodByName("String") m := v.MethodByName("String")
@ -236,17 +240,41 @@ var dataLogChan chan DataLogRow
func dataLogWriter() { func dataLogWriter() {
dataLogChan := make(chan DataLogRow, 10240) dataLogChan := make(chan DataLogRow, 10240)
db, err := sql.Open("sqlite3", "./test.db") // Check if we need to create a new database.
createDatabase := false
if _, err := os.Stat(dataLogFile); os.IsNotExist(err) {
createDatabase = true
log.Printf("creating new database '%s'.\n", dataLogFile)
}
db, err := sql.Open("sqlite3", dataLogFile)
if err != nil { if err != nil {
fmt.Printf("sql.Open(): %s\n", err.Error()) log.Printf("sql.Open(): %s\n", err.Error())
} }
defer db.Close() defer db.Close()
// Do we need to create the database?
if createDatabase {
makeTable(dataLogTimestamp, "timestamp", db)
makeTable(mySituation, "mySituation", db)
makeTable(globalStatus, "status", db)
makeTable(globalSettings, "settings", db)
makeTable(TrafficInfo{}, "traffic", db)
}
for { for {
//FIXME: measure latency from here to end of block. Messages may need to be timestamped *before* executing everything here. //FIXME: measure latency from here to end of block. Messages may need to be timestamped *before* executing everything here.
r := <-dataLogChan r := <-dataLogChan
if r.tbl == "mySituation" { if r.tbl == "mySituation" && isGPSClockValid() {
//TODO: Piggyback a GPS time update from this update. // Piggyback a GPS time update from this update.
if t, ok := r.data.(SituationData); ok {
dataLogTimestamp.id = 0
dataLogTimestamp.Time_type_preference = 1 // gpsClock.
dataLogTimestamp.StratuxClock_value = stratuxClock.Time
dataLogTimestamp.GPSClock_value = t.GPSTime
dataLogTimestamp.PreferredTime_value = t.GPSTime
}
} }
// Check if our time bucket has expired or has never been entered. // Check if our time bucket has expired or has never been entered.
@ -257,50 +285,22 @@ func dataLogWriter() {
} }
} }
type SituationData struct { func logSituation() {
// From GPS. dataLogChan <- DataLogRow{tbl: "mySituation", data: mySituation}
LastFixSinceMidnightUTC float32
Lat float32
Lng float32
Quality uint8
HeightAboveEllipsoid float32 // GPS height above WGS84 ellipsoid, ft. This is specified by the GDL90 protocol, but most EFBs use MSL altitude instead. HAE is about 70-100 ft below GPS MSL altitude over most of the US.
GeoidSep float32 // geoid separation, ft, MSL minus HAE (used in altitude calculation)
Satellites uint16 // satellites used in solution
SatellitesTracked uint16 // satellites tracked (almanac data received)
SatellitesSeen uint16 // satellites seen (signal received)
Accuracy float32 // 95% confidence for horizontal position, meters.
NACp uint8 // NACp categories are defined in AC 20-165A
Alt float32 // Feet MSL
AccuracyVert float32 // 95% confidence for vertical position, meters
GPSVertVel float32 // GPS vertical velocity, feet per second
LastFixLocalTime time.Time
TrueCourse uint16
GroundSpeed uint16
LastGroundTrackTime time.Time
LastGPSTimeTime time.Time
LastNMEAMessage time.Time // time valid NMEA message last seen
// From BMP180 pressure sensor.
Temp float64
Pressure_alt float64
LastTempPressTime time.Time
// From MPU6050 accel/gyro.
Pitch float64
Roll float64
Gyro_heading float64
LastAttitudeTime time.Time
} }
func main() { func logStatus() {
db, err := sql.Open("sqlite3", "./test.db") dataLogChan <- DataLogRow{tbl: "status", data: globalStatus}
if err != nil { }
fmt.Printf("sql.Open(): %s\n", err.Error())
} func logSettings() {
defer db.Close() dataLogChan <- DataLogRow{tbl: "settings", data: globalSettings}
}
e := SituationData{}
//makeTable(e, "situation", db) func logTraffic(ti TrafficInfo) {
i := insertData(e, "situation", db) dataLogChan <- DataLogRow{tbl: "traffic", data: ti}
fmt.Printf("insert id=%d\n", i) }
func initDataLog() {
go dataLogWriter()
} }

Wyświetl plik

@ -44,6 +44,7 @@ const (
maxDatagramSize = 8192 maxDatagramSize = 8192
maxUserMsgQueueSize = 25000 // About 10MB per port per connected client. maxUserMsgQueueSize = 25000 // About 10MB per port per connected client.
logDirectory = "/var/log/stratux" logDirectory = "/var/log/stratux"
dataLogFile = "/var/log/stratux.sqlite"
UPLINK_BLOCK_DATA_BITS = 576 UPLINK_BLOCK_DATA_BITS = 576
UPLINK_BLOCK_BITS = (UPLINK_BLOCK_DATA_BITS + 160) UPLINK_BLOCK_BITS = (UPLINK_BLOCK_DATA_BITS + 160)
@ -1361,6 +1362,8 @@ func main() {
globalSettings.ReplayLog = true globalSettings.ReplayLog = true
} }
//FIXME: Only do this if data logging is enabled.
initDataLog()
// Set up the replay logs. Keep these files open in any case, even if replay logging is disabled. // Set up the replay logs. Keep these files open in any case, even if replay logging is disabled.
if uatwt, err := openReplay(uatReplayLog, !developerMode); err != nil { if uatwt, err := openReplay(uatReplayLog, !developerMode); err != nil {