Conflicts:
	main/gen_gdl90.go
	web/plates/js/settings.js
pull/427/head
Ryan C. Braun 2016-05-04 05:50:52 +00:00
commit 6ae392af6d
8 zmienionych plików z 170 dodań i 42 usunięć

Wyświetl plik

@ -43,6 +43,9 @@ type StratuxStartup struct {
Fill string
}
var dataLogStarted bool
var dataLogReadyToWrite bool
var stratuxStartupID int64
var dataLogTimestamps []StratuxTimestamp
var dataLogCurTimestamp int64 // Current timestamp bucket. This is an index on dataLogTimestamps which is not necessarily the db id.
@ -350,11 +353,13 @@ type DataLogRow struct {
var dataLogChan chan DataLogRow
var shutdownDataLog chan bool
var shutdownDataLogWriter chan bool
var dataLogWriteChan chan DataLogRow
func dataLogWriter(db *sql.DB) {
dataLogWriteChan = make(chan DataLogRow, 10240)
shutdownDataLogWriter = make(chan bool)
// The write queue. As data comes in via dataLogChan, it is timestamped and stored.
// When writeTicker comes up, the queue is emptied.
writeTicker := time.NewTicker(10 * time.Second)
@ -400,12 +405,21 @@ func dataLogWriter(db *sql.DB) {
}
if timeElapsed.Seconds() > 10.0 {
log.Printf("WARNING! SQLite logging is behind. Last write took %.1f seconds.\n", float64(timeElapsed.Seconds()))
dataLogCriticalErr := fmt.Errorf("WARNING! SQLite logging is behind. Last write took %.1f seconds.\n", float64(timeElapsed.Seconds()))
addSystemError(dataLogCriticalErr)
}
case <-shutdownDataLogWriter: // Received a message on the channel to initiate a graceful shutdown, and to command dataLog() to shut down
log.Printf("datalog.go: dataLogWriter() received shutdown message with rowsQueuedForWrite = %d\n", len(rowsQueuedForWrite))
shutdownDataLog <- true
return
}
}
log.Printf("datalog.go: dataLogWriter() shutting down\n")
}
func dataLog() {
dataLogStarted = true
log.Printf("datalog.go: dataLog() started\n")
dataLogChan = make(chan DataLogRow, 10240)
shutdownDataLog = make(chan bool)
dataLogTimestamps = make([]StratuxTimestamp, 0)
@ -430,7 +444,13 @@ func dataLog() {
if err != nil {
log.Printf("sql.Open(): %s\n", err.Error())
}
defer db.Close()
defer func() {
db.Close()
dataLogStarted = false
//close(dataLogChan)
log.Printf("datalog.go: dataLog() has closed DB in %s\n", dataLogFile)
}()
_, err = db.Exec("PRAGMA journal_mode=WAL")
if err != nil {
@ -441,6 +461,7 @@ func dataLog() {
log.Printf("db.Exec('PRAGMA journal_mode=WAL') err: %s\n", err.Error())
}
//log.Printf("Starting dataLogWriter\n") // REMOVE -- DEBUG
go dataLogWriter(db)
// Do we need to create the database?
@ -459,6 +480,8 @@ func dataLog() {
// The first entry to be created is the "startup" entry.
stratuxStartupID = insertData(StratuxStartup{}, "startup", db, 0)
dataLogReadyToWrite = true
//log.Printf("Entering dataLog read loop\n") //REMOVE -- DEBUG
for {
select {
case r := <-dataLogChan:
@ -469,10 +492,13 @@ func dataLog() {
r.ts_num = dataLogCurTimestamp
// Queue it for the scheduled write.
dataLogWriteChan <- r
case <-shutdownDataLog: // Received a message on the channel (anything). Graceful shutdown (defer statement).
case <-shutdownDataLog: // Received a message on the channel to complete a graceful shutdown (see the 'defer func()...' statement above).
log.Printf("datalog.go: dataLog() received shutdown message\n")
return
}
}
log.Printf("datalog.go: dataLog() shutting down\n")
close(shutdownDataLog)
}
/*
@ -495,46 +521,118 @@ func setDataLogTimeWithGPS(sit SituationData) {
}
}
/*
logSituation(), logStatus(), ... pass messages from other functions to the logging
engine. These are only read into `dataLogChan` if the Replay Log is toggled on,
and if the log system is ready to accept writes.
*/
func isDataLogReady() bool {
return dataLogReadyToWrite
}
func logSituation() {
if globalSettings.ReplayLog {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "mySituation", data: mySituation}
}
}
func logStatus() {
dataLogChan <- DataLogRow{tbl: "status", data: globalStatus}
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "status", data: globalStatus}
}
}
func logSettings() {
dataLogChan <- DataLogRow{tbl: "settings", data: globalSettings}
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "settings", data: globalSettings}
}
}
func logTraffic(ti TrafficInfo) {
if globalSettings.ReplayLog {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "traffic", data: ti}
}
}
func logMsg(m msg) {
if globalSettings.ReplayLog {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "messages", data: m}
}
}
func logESMsg(m esmsg) {
if globalSettings.ReplayLog {
if globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "es_messages", data: m}
}
}
func logDump1090TermMessage(m Dump1090TermMessage) {
if globalSettings.DEBUG && globalSettings.ReplayLog {
if globalSettings.DEBUG && globalSettings.ReplayLog && isDataLogReady() {
dataLogChan <- DataLogRow{tbl: "dump1090_terminal", data: m}
}
}
func initDataLog() {
//log.Printf("dataLogStarted = %t. dataLogReadyToWrite = %t\n", dataLogStarted, dataLogReadyToWrite) //REMOVE -- DEBUG
insertString = make(map[string]string)
insertBatchIfs = make(map[string][][]interface{})
go dataLog()
go dataLogWatchdog()
//log.Printf("datalog.go: initDataLog() complete.\n") //REMOVE -- DEBUG
}
/*
dataLogWatchdog(): Watchdog function to control startup / shutdown of data logging subsystem.
Called by initDataLog as a goroutine. It iterates once per second to determine if
globalSettings.ReplayLog has toggled. If logging was switched from off to on, it starts
datalog() as a goroutine. If the log is running and we want it to stop, it calls
closeDataLog() to turn off the input channels, close the log, and tear down the dataLog
and dataLogWriter goroutines.
*/
func dataLogWatchdog() {
for {
if globalSettings.DEBUG {
log.Printf("datalog.go: Watchdog loop iterating. dataLogStarted = %t\n", dataLogStarted)
}
if !dataLogStarted && globalSettings.ReplayLog { // case 1: sqlite logging isn't running, and we want to start it
log.Printf("datalog.go: Watchdog wants to START logging.\n")
go dataLog()
} else if dataLogStarted && !globalSettings.ReplayLog { // case 2: sqlite logging is running, and we want to shut it down
log.Printf("datalog.go: Watchdog wants to STOP logging.\n")
closeDataLog()
}
//log.Printf("Watchdog iterated.\n") //REMOVE -- DEBUG
time.Sleep(1 * time.Second)
//log.Printf("Watchdog sleep over.\n") //REMOVE -- DEBUG
}
}
/*
closeDataLog(): Handler for graceful shutdown of data logging goroutines. It is called by
by dataLogWatchdog(), gracefulShutdown(), and by any other function (disk space monitor?)
that needs to be able to shut down sqlite logging without corrupting data or blocking
execution.
This function turns off log message reads into the dataLogChan receiver, and sends a
message to a quit channel ('shutdownDataLogWriter`) in dataLogWriter(). dataLogWriter()
then sends a message to a quit channel to 'shutdownDataLog` in dataLog() to close *that*
goroutine. That function sets dataLogStarted=false once the logfile is closed. By waiting
for that signal, closeDataLog() won't exit until the log is safely written. This prevents
data loss on shutdown.
*/
func closeDataLog() {
//log.Printf("closeDataLog(): dataLogStarted = %t\n", dataLogStarted) //REMOVE -- DEBUG
dataLogReadyToWrite = false // prevent any new messages from being sent down the channels
log.Printf("datalog.go: Starting data log shutdown\n")
shutdownDataLogWriter <- true //
defer close(shutdownDataLogWriter) // ... and close the channel so subsequent accidental writes don't stall execution
log.Printf("datalog.go: Waiting for shutdown signal from dataLog()")
for dataLogStarted {
//log.Printf("closeDataLog(): dataLogStarted = %t\n", dataLogStarted) //REMOVE -- DEBUG
time.Sleep(50 * time.Millisecond)
}
log.Printf("datalog.go: Data log shutdown successful.\n")
}

Wyświetl plik

@ -721,7 +721,7 @@ func cpuTempMonitor() {
func updateStatus() {
if mySituation.Quality == 2 {
globalStatus.GPS_solution = "DGPS (SBAS / WAAS)"
globalStatus.GPS_solution = "GPS + SBAS (WAAS / EGNOS)"
} else if mySituation.Quality == 1 {
globalStatus.GPS_solution = "3D GPS"
} else if mySituation.Quality == 6 {
@ -965,17 +965,18 @@ func getProductNameFromId(product_id int) string {
}
type settings struct {
UAT_Enabled bool
ES_Enabled bool
Ping_Enabled bool
GPS_Enabled bool
NetworkOutputs []networkConnection
AHRS_Enabled bool
DEBUG bool
ReplayLog bool
PPM int
OwnshipModeS string
WatchList string
UAT_Enabled bool
ES_Enabled bool
Ping_Enabled bool
GPS_Enabled bool
NetworkOutputs []networkConnection
AHRS_Enabled bool
DisplayTrafficSource bool
DEBUG bool
ReplayLog bool
PPM int
OwnshipModeS string
WatchList string
}
type status struct {
@ -1026,6 +1027,7 @@ func defaultSettings() {
}
globalSettings.AHRS_Enabled = false
globalSettings.DEBUG = false
globalSettings.DisplayTrafficSource = false
globalSettings.ReplayLog = false //TODO: 'true' for debug builds.
globalSettings.OwnshipModeS = "F00000"
}
@ -1196,9 +1198,14 @@ func gracefulShutdown() {
// Shut down SDRs.
sdrKill()
pingKill()
//TODO: Any other graceful shutdown functions.
// Shut down data logging.
shutdownDataLog <- true
if dataLogStarted {
closeDataLog()
}
//TODO: Any other graceful shutdown functions.
os.Exit(1)
}

Wyświetl plik

@ -207,6 +207,8 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
globalSettings.AHRS_Enabled = val.(bool)
case "DEBUG":
globalSettings.DEBUG = val.(bool)
case "DisplayTrafficSource":
globalSettings.DisplayTrafficSource = val.(bool)
case "ReplayLog":
v := val.(bool)
if v != globalSettings.ReplayLog { // Don't mark the files unless there is a change.

Wyświetl plik

@ -33,11 +33,12 @@ type networkMessage struct {
}
type networkConnection struct {
Conn *net.UDPConn
Ip string
Port uint32
Capability uint8
messageQueue [][]byte // Device message queue.
Conn *net.UDPConn
Ip string
Port uint32
Capability uint8
messageQueue [][]byte // Device message queue.
MessageQueueLen int // Length of the message queue. For debugging.
/*
Sleep mode/throttle variables. "sleep mode" is actually now just a very reduced packet rate, since we don't know positively
when a client is ready to accept packets - we just assume so if we don't receive ICMP Unreachable packets in 5 secs.
@ -292,6 +293,8 @@ func messageQueueSender() {
outSockets[k] = tmpConn
*/
}
netconn.MessageQueueLen = len(netconn.messageQueue)
outSockets[k] = netconn
}
if stratuxClock.Since(lastQueueTimeChange) >= 5*time.Second {

Wyświetl plik

@ -130,15 +130,13 @@ func initGPSSerial() bool {
baudrate := int(9600)
isSirfIV := bool(false)
if _, err := os.Stat("/dev/ttyUSB0"); err == nil {
if _, err := os.Stat("/dev/ttyACM0"); err == nil { // u-blox receivers on native USB connection
device = "/dev/ttyACM0"
} else if _, err := os.Stat("/dev/ttyUSB0"); err == nil { // USB-to-serial bridge. Typical use is BU-353-S4 SIRF IV receivers, but could also be for other devices or serial-out (better detection is TODO)
isSirfIV = true
baudrate = 4800
device = "/dev/ttyUSB0"
} else if _, err := os.Stat("/dev/ttyACM0"); err == nil {
device = "/dev/ttyACM0"
//} else if _, err := os.Stat("/dev/ttyS0"); err == nil { // ttyS0 appears to be mini UART on RPi 3
// device = "/dev/ttyS0"
} else if _, err := os.Stat("/dev/ttyAMA0"); err == nil { // ttyAMA0 is PL011 UART (GPIO pins 8 and 10) on all RPi
} else if _, err := os.Stat("/dev/ttyAMA0"); err == nil { // ttyAMA0 is PL011 UART (GPIO pins 8 and 10) on all RPi.
device = "/dev/ttyAMA0"
} else {
log.Printf("No suitable device found.\n")
@ -1166,8 +1164,22 @@ func isGPSConnected() bool {
return stratuxClock.Since(mySituation.LastValidNMEAMessageTime) < 5*time.Second
}
/*
isGPSValid returns true only if a valid position fix has been seen in the last 15 seconds,
and if the GPS subsystem has recently detected a GPS device.
If false, 'Quality` is set to 0 ("No fix"), as is the number of satellites in solution.
*/
func isGPSValid() bool {
return stratuxClock.Since(mySituation.LastFixLocalTime) < 15*time.Second
isValid := false
if (stratuxClock.Since(mySituation.LastFixLocalTime) < 15*time.Second) && globalStatus.GPS_connected && mySituation.Quality > 0 {
isValid = true
} else {
mySituation.Quality = 0
mySituation.Satellites = 0
}
return isValid
}
func isGPSGroundTrackValid() bool {

Wyświetl plik

@ -400,7 +400,7 @@ func parseDownlinkReport(s string, signalLevel int) {
}
// This is a hack to show the source of the traffic on moving maps.
if globalSettings.DEBUG {
if globalSettings.DisplayTrafficSource {
type_code := " "
switch ti.TargetType {
case TARGET_TYPE_ADSB:
@ -837,7 +837,7 @@ func esListen() {
// This is a hack to show the source of the traffic on moving maps.
if globalSettings.DEBUG {
if globalSettings.DisplayTrafficSource {
type_code := " "
switch ti.TargetType {
case TARGET_TYPE_ADSB:

Wyświetl plik

@ -6,7 +6,7 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
$scope.$parent.helppage = 'plates/settings-help.html';
var toggles = ['UAT_Enabled', 'ES_Enabled', 'Ping_Enabled', 'GPS_Enabled', 'AHRS_Enabled', 'DEBUG', 'ReplayLog']; // DEBUG is 'DspTrafficSrc'
var toggles = ['UAT_Enabled', 'ES_Enabled', 'Ping_Enabled', 'GPS_Enabled', 'AHRS_Enabled', 'DisplayTrafficSource', 'DEBUG', 'ReplayLog'];
var settings = {};
for (i = 0; i < toggles.length; i++) {
settings[toggles[i]] = undefined;
@ -22,7 +22,7 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
$scope.Ping_Enabled = settings.Ping_Enabled;
$scope.GPS_Enabled = settings.GPS_Enabled;
$scope.AHRS_Enabled = settings.AHRS_Enabled;
$scope.PowerSave = settings.PowerSave
$scope.DisplayTrafficSource = settings.DisplayTrafficSource;
$scope.DEBUG = settings.DEBUG;
$scope.ReplayLog = settings.ReplayLog;
$scope.PPM = settings.PPM;

Wyświetl plik

@ -43,13 +43,19 @@
<div class="panel-heading">Diagnostics</div>
<div class="panel-body">
<div class="form-group">
<label class="control-label col-xs-7">Traffic Markings</label>
<label class="control-label col-xs-7">Show Traffic Source in Callsign</label>
<div class="col-xs-5">
<ui-switch ng-model='DisplayTrafficSource' settings-change></ui-switch>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-7">Verbose Message Log</label>
<div class="col-xs-5">
<ui-switch ng-model='DEBUG' settings-change></ui-switch>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-7">Record Logs</label>
<label class="control-label col-xs-7">Record Replay Logs</label>
<div class="col-xs-5">
<ui-switch ng-model='ReplayLog' settings-change></ui-switch>
</div>