Merge remote-tracking branch 'origin/master'

# Conflicts:
#	selfupdate/makeupdate.sh
adsbexchange
cyoung 2018-01-26 10:48:55 -05:00
commit 7338ad4336
18 zmienionych plików z 224 dodań i 185 usunięć

2
.gitmodules vendored
Wyświetl plik

@ -1,6 +1,6 @@
[submodule "dump1090"]
path = dump1090
url = https://github.com/AvSquirrel/dump1090
url = https://github.com/stratux/dump1090
[submodule "goflying"]
path = goflying
url = https://github.com/cyoung/goflying

Wyświetl plik

@ -14,7 +14,7 @@ all:
make ahrs_approx xdump978 xdump1090 xgen_gdl90 $(PLATFORMDEPENDENT)
xgen_gdl90:
go get -t -d -v ./main ./test ./godump978 ./uatparse ./sensors
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
fancontrol:

Wyświetl plik

@ -47,3 +47,5 @@ Jet tests (high gain antennas):
* Embraer ERJ 145
* Cessna Citation 501
* Lear 35
* Rockwell B-1b
* Boeing C-17

Wyświetl plik

@ -5,13 +5,13 @@ machine:
dependencies:
pre:
- sudo apt-get update; sudo apt-get install libusb-1.0-0-dev; cd ~/; git clone https://github.com/jpoirier/librtlsdr; cd librtlsdr; mkdir build; cd build; cmake ../; make; sudo make install; sudo ldconfig; cd ~/; mkdir gopath; cd ~/; mkdir gopath; wget https://storage.googleapis.com/golang/go1.6.src.tar.gz; tar -zxvf go1.6.src.tar.gz; cd go/src; export GOROOT_BOOTSTRAP=/usr/local/go; ./make.bash; echo $PATH; echo $GOPATH; go version; env
- sudo apt-get update; sudo apt-get install libusb-1.0-0-dev mercurial; cd ~/; git clone https://github.com/jpoirier/librtlsdr; cd librtlsdr; mkdir build; cd build; cmake ../; make; sudo make install; sudo ldconfig; cd ~/; rm -rf gopath; mkdir gopath; wget https://dl.google.com/go/go1.9.2.linux-amd64.tar.gz; tar -zxvf go1.9.2.linux-amd64.tar.gz; go version; env
override:
- cd .. ; rm -rf stratux ; git clone --recursive https://github.com/cyoung/stratux ; cd stratux ; git config --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*" ; git fetch origin ; BRANCH=`echo "$CIRCLE_BRANCH" | sed 's/pull\//pr\//g'` ; git checkout $BRANCH ; make
test:
override:
- make test
- make
deployment:
production:

Wyświetl plik

@ -11,6 +11,7 @@ iface wlan0 inet static
address 10.26.36.1
netmask 255.255.255.0
post-up /usr/sbin/stratux-wifi.sh
wireless-power off
auto eth0:0
iface eth0:0 inet static

Wyświetl plik

@ -0,0 +1,32 @@
# see "man logrotate" for details
# rotate log files weekly
daily
# keep 2 days worth of backlogs
rotate 2
# create new (empty) log files after rotating old ones
create
# uncomment this if you want your log files compressed
compress
# packages drop log rotation information into this directory
include /etc/logrotate.d
# no packages own wtmp, or btmp -- we'll rotate them here
/var/log/wtmp {
missingok
monthly
create 0664 root utmp
rotate 1
}
/var/log/btmp {
missingok
monthly
create 0660 root utmp
rotate 1
}
# system-specific logs may be configured here

Wyświetl plik

@ -61,6 +61,9 @@ chmod 755 mnt/usr/sbin/sdr-tool.sh
#ping udev
cp -f 99-uavionix.rules mnt/etc/udev/rules.d
#logrotate conf
cp -f logrotate.conf mnt/etc/logrotate.conf
#fan/temp control script
#remove old script
rm -rf mnt/usr/bin/fancontrol.py

Wyświetl plik

@ -17,6 +17,13 @@ if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
#
# Rotate logs on boot.
#
/usr/sbin/logrotate /etc/logrotate.conf
/usr/bin/stratux-screen.py start
route add default gw 10.26.36.1

Wyświetl plik

@ -1172,12 +1172,25 @@ func addSystemError(err error) {
globalStatus.Errors = append(globalStatus.Errors, err.Error())
}
var systemErrsMutex *sync.Mutex
var systemErrs map[string]string
func addSingleSystemErrorf(ident string, format string, a ...interface{}) {
systemErrsMutex.Lock()
if _, ok := systemErrs[ident]; !ok {
// Error hasn't been thrown yet.
systemErrs[ident] = fmt.Sprintf(format, a...)
globalStatus.Errors = append(globalStatus.Errors, systemErrs[ident])
log.Printf("Added critical system error: %s\n", systemErrs[ident])
}
// Do nothing on this call if the error has already been thrown.
systemErrsMutex.Unlock()
}
func saveSettings() {
fd, err := os.OpenFile(configLocation, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0644))
if err != nil {
err_ret := fmt.Errorf("can't save settings %s: %s", configLocation, err.Error())
addSystemError(err_ret)
log.Printf("%s\n", err_ret.Error())
addSingleSystemErrorf("save-settings", "can't save settings %s: %s", configLocation, err.Error())
return
}
defer fd.Close()
@ -1225,7 +1238,6 @@ func fsWriteTest(dir string) error {
func printStats() {
statTimer := time.NewTicker(30 * time.Second)
diskUsageWarning := false
for {
<-statTimer.C
var memstats runtime.MemStats
@ -1250,10 +1262,8 @@ func printStats() {
log.Printf("- " + strings.Join(sensorsOutput, ", ") + "\n")
}
// Check if we're using more than 95% of the free space. If so, throw a warning (only once).
if !diskUsageWarning && usage.Usage() > 0.95 {
err_p := fmt.Errorf("Disk bytes used = %s (%.1f %%), Disk bytes free = %s (%.1f %%)", humanize.Bytes(usage.Used()), 100*usage.Usage(), humanize.Bytes(usage.Free()), 100*(1-usage.Usage()))
addSystemError(err_p)
diskUsageWarning = true
if usage.Usage() > 0.95 {
addSingleSystemErrorf("disk-space", "Disk bytes used = %s (%.1f %%), Disk bytes free = %s (%.1f %%)", humanize.Bytes(usage.Used()), 100*usage.Usage(), humanize.Bytes(usage.Free()), 100*(1-usage.Usage()))
}
logStatus()
}
@ -1385,6 +1395,10 @@ func main() {
mySituation.muBaro = &sync.Mutex{}
mySituation.muSatellite = &sync.Mutex{}
// Set up system error tracking.
systemErrsMutex = &sync.Mutex{}
systemErrs = make(map[string]string)
// Set up status.
globalStatus.Version = stratuxVersion
globalStatus.Build = stratuxBuild
@ -1410,13 +1424,11 @@ func main() {
vtF, err := strconv.ParseFloat(vtS, 32)
if err == nil {
if vtF < 8.0 {
var err_os error
if globalStatus.HardwareBuild == "FlightBox" {
err_os = fmt.Errorf("You are running an old Stratux image that can't be updated fully and is now deprecated. Visit https://www.openflightsolutions.com/flightbox/image-update-required for further information.")
addSingleSystemErrorf("deprecated-image", "You are running an old Stratux image that can't be updated fully and is now deprecated. Visit https://www.openflightsolutions.com/flightbox/image-update-required for further information.")
} else {
err_os = fmt.Errorf("You are running an old Stratux image that can't be updated fully and is now deprecated. Visit http://stratux.me/ to update using the latest release image.")
addSingleSystemErrorf("deprecated-image", "You are running an old Stratux image that can't be updated fully and is now deprecated. Visit http://stratux.me/ to update using the latest release image.")
}
addSystemError(err_os)
} else {
// Running Jessie or better. Remove some old init.d files.
// This made its way in here because /etc/init.d/stratux invokes the update script, which can't delete the init.d file.
@ -1453,9 +1465,7 @@ func main() {
// Duplicate log.* output to debugLog.
fp, err := os.OpenFile(debugLogf, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
err_log := fmt.Errorf("Failed to open '%s': %s", debugLogf, err.Error())
addSystemError(err_log)
log.Printf("%s\n", err_log.Error())
addSingleSystemErrorf(debugLogf, "Failed to open '%s': %s", debugLogf, err.Error())
} else {
defer fp.Close()
// Keep the logfile handle for later use

Wyświetl plik

@ -10,6 +10,7 @@
package main
import (
"archive/zip"
"encoding/hex"
"encoding/json"
"fmt"
@ -21,13 +22,12 @@ import (
"net/http"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"syscall"
"text/template"
"time"
"archive/zip"
"path/filepath"
)
type SettingMessage struct {
@ -403,7 +403,7 @@ func handleDeleteAHRSLogFiles(w http.ResponseWriter, r *http.Request) {
var fn string
for _, f := range files {
fn = f.Name()
if v, _ := filepath.Match("sensors_*.csv", fn) ; v {
if v, _ := filepath.Match("sensors_*.csv", fn); v {
os.Remove("/var/log/" + fn)
log.Printf("Deleting AHRS log file %s\n", fn)
}
@ -654,14 +654,12 @@ func defaultServer(w http.ResponseWriter, r *http.Request) {
func handleroPartitionRebuild(w http.ResponseWriter, r *http.Request) {
out, err := exec.Command("/usr/sbin/rebuild_ro_part.sh").Output()
var ret_err error
if err != nil {
ret_err = fmt.Errorf("Rebuild RO Partition error: %s", err.Error())
addSingleSystemErrorf("partition-rebuild", "Rebuild RO Partition error: %s", err.Error())
} else {
ret_err = fmt.Errorf("Rebuild RO Partition success: %s", out)
addSingleSystemErrorf("partition-rebuild", "Rebuild RO Partition success: %s", out)
}
addSystemError(ret_err)
}
// https://gist.github.com/alexisrobert/982674.

Wyświetl plik

@ -10,8 +10,6 @@
package main
import (
"errors"
"fmt"
"github.com/tarm/serial"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
@ -76,19 +74,16 @@ const (
extra_hosts_file = "/etc/stratux-static-hosts.conf"
)
var dhcpLeaseFileWarning bool
var dhcpLeaseDirectoryLastTest time.Time // Last time fsWriteTest() was run on the DHCP lease directory.
// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
// Do a write test. Even if we are able to read the file, it may be out of date because there's a fs write issue.
// Only perform the test once every 5 minutes to minimize writes.
if !dhcpLeaseFileWarning && (stratuxClock.Since(dhcpLeaseDirectoryLastTest) >= 5*time.Minute) {
if stratuxClock.Since(dhcpLeaseDirectoryLastTest) >= 5*time.Minute {
err := fsWriteTest(dhcp_lease_dir)
if err != nil {
err_p := fmt.Errorf("Write error on '%s', your EFB may have issues receiving weather and traffic.", dhcp_lease_dir)
addSystemError(err_p)
dhcpLeaseFileWarning = true
addSingleSystemErrorf("fs-write", "Write error on '%s', your EFB may have issues receiving weather and traffic.", dhcp_lease_dir)
}
dhcpLeaseDirectoryLastTest = stratuxClock.Time
}
@ -602,8 +597,6 @@ func networkStatsCounter() {
*/
func ffMonitor() {
ff_warned := false // Has a warning been issued via globalStatus.Errors?
addr := net.UDPAddr{Port: 50113, IP: net.ParseIP("0.0.0.0")}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
@ -637,11 +630,7 @@ func ffMonitor() {
if strings.HasPrefix(s, "i-want-to-play-ffm-udp") || strings.HasPrefix(s, "i-can-play-ffm-udp") || strings.HasPrefix(s, "i-cannot-play-ffm-udp") {
p.FFCrippled = true
//FIXME: AHRS output doesn't need to be disabled globally, just on the ForeFlight client IPs.
if !ff_warned {
e := errors.New("Stratux is not supported by your EFB app. Your EFB app is known to regularly make changes that cause compatibility issues with Stratux. See the README for a list of apps that officially support Stratux.")
addSystemError(e)
ff_warned = true
}
addSingleSystemErrorf("ff-warn", "Stratux is not supported by your EFB app. Your EFB app is known to regularly make changes that cause compatibility issues with Stratux. See the README for a list of apps that officially support Stratux.")
}
outSockets[ffIpAndPort] = p
netMutex.Unlock()

Wyświetl plik

@ -10,7 +10,6 @@
package main
import (
"fmt"
"log"
"os/exec"
"regexp"
@ -484,8 +483,7 @@ func sdrWatcher() {
} else if globalSettings.DeveloperMode {
// Throw a "critical error" if developer mode is enabled. Alerts the developer that the daemon was restarted (possibly)
// unexpectedly.
daemonRestartedErr := fmt.Errorf("System uptime %d seconds. Daemon was restarted.\n", info.Uptime)
addSystemError(daemonRestartedErr)
addSingleSystemErrorf("restart-warn", "System uptime %d seconds. Daemon was restarted.\n", info.Uptime)
}
}

Wyświetl plik

@ -22,13 +22,13 @@ const (
)
var (
i2cbus embd.I2CBus
myPressureReader sensors.PressureReader
myIMUReader sensors.IMUReader
cal chan (string)
analysisLogger *ahrs.AHRSLogger
ahrsCalibrating bool
logMap map[string]interface{}
i2cbus embd.I2CBus
myPressureReader sensors.PressureReader
myIMUReader sensors.IMUReader
cal chan (string)
analysisLogger *ahrs.AHRSLogger
ahrsCalibrating bool
logMap map[string]interface{}
)
func initI2CSensors() {
@ -52,7 +52,6 @@ func pollSensors() {
// If it's not currently connected, try connecting to IMU
if globalSettings.IMU_Sensor_Enabled && !globalStatus.IMUConnected {
log.Println("AHRS Info: attempting IMU connection.")
globalStatus.IMUConnected = initIMU() // I2C accel/gyro/mag.
}
}
@ -62,13 +61,11 @@ func initPressureSensor() (ok bool) {
bmp, err := sensors.NewBMP280(&i2cbus, 100*time.Millisecond)
if err == nil {
myPressureReader = bmp
log.Println("AHRS Info: Successfully initialized BMP280")
return true
}
//TODO westphae: make bmp180.go to fit bmp interface
log.Println("AHRS Info: couldn't initialize BMP280 or BMP180")
return false
}
@ -93,14 +90,14 @@ func tempAndPressureSender() {
// Read temperature and pressure altitude.
temp, err = myPressureReader.Temperature()
if err != nil {
log.Printf("AHRS Error: Couldn't read temperature from sensor: %s", err)
addSingleSystemErrorf("pressure-sensor-temp-read", "AHRS Error: Couldn't read temperature from sensor: %s", err)
}
press, err = myPressureReader.Pressure()
if err != nil {
log.Printf("AHRS Error: Couldn't read pressure from sensor: %s", err)
addSingleSystemErrorf("pressure-sensor-pressure-read", "AHRS Error: Couldn't read pressure from sensor: %s", err)
failNum++
if failNum > numRetries {
log.Printf("AHRS Error: Couldn't read pressure from sensor %d times, closing BMP: %s", failNum, err)
// log.Printf("AHRS Error: Couldn't read pressure from sensor %d times, closing BMP: %s", failNum, err)
myPressureReader.Close()
globalStatus.BMPConnected = false // Try reconnecting a little later
break
@ -129,16 +126,16 @@ func initIMU() (ok bool) {
imu, err := sensors.NewMPU9250()
if err == nil {
myIMUReader = imu
log.Println("AHRS Info: Successfully connected MPU9250")
return true
}
// TODO westphae: try to connect to MPU9150 or other IMUs.
log.Println("AHRS Error: couldn't initialize an IMU")
return false
}
//FIXME: Shoud be moved to managementinterface.go and standardized on management interface port.
func sensorAttitudeSender() {
var (
t time.Time
@ -147,7 +144,6 @@ func sensorAttitudeSender() {
failNum uint8
)
log.Println("AHRS Info: initializing new Simple AHRS")
s := ahrs.NewSimpleAHRS()
m := ahrs.NewMeasurement()
cal = make(chan (string), 1)
@ -155,9 +151,8 @@ func sensorAttitudeSender() {
// Set up loggers for analysis
ahrswebListener, err := ahrsweb.NewKalmanListener()
if err != nil {
log.Printf("AHRS Info: couldn't start ahrswebListener: %s\n", err.Error())
// addSingleSystemErrorf("ahrs-web-start", "AHRS Info: couldn't start ahrswebListener: %s\n", err.Error())
} else {
log.Println("AHRS Info: ahrswebListener started on port 8000")
defer ahrswebListener.Close()
}
@ -165,7 +160,7 @@ func sensorAttitudeSender() {
timer := time.NewTicker(50 * time.Millisecond) // ~20Hz update.
for {
// Set sensor gyro calibrations
if c, d := &globalSettings.C, &globalSettings.D; d[0]*d[0] + d[1]*d[1] + d[2]*d[2] > 0 {
if c, d := &globalSettings.C, &globalSettings.D; d[0]*d[0]+d[1]*d[1]+d[2]*d[2] > 0 {
s.SetCalibrations(c, d)
log.Printf("AHRS Info: IMU Calibrations read from settings: accel %6f %6f %6f; gyro %6f %6f %6f\n",
c[0], c[1], c[2], d[0], d[1], d[2])
@ -178,7 +173,7 @@ func sensorAttitudeSender() {
}
// Set sensor quaternion
if f := &globalSettings.SensorQuaternion; f[0]*f[0] + f[1]*f[1] + f[2]*f[2] + f[3]*f[3] > 0 {
if f := &globalSettings.SensorQuaternion; f[0]*f[0]+f[1]*f[1]+f[2]*f[2]+f[3]*f[3] > 0 {
s.SetSensorQuaternion(f)
} else {
select { // Don't block if cal isn't receiving: only need one calibration in the queue at a time.

Wyświetl plik

@ -55,7 +55,7 @@ Some 1090ES transponders will send the actual registration number of the aircraf
a squawk code.
### Additional data available to EFBs
### Additional data/control available to EFBs
Stratux makes available a webserver to retrieve statistics which may be useful to EFBs:
@ -262,3 +262,16 @@ Subsequent update (2837120 = 2B4A80 reports a newer position, altitude increased
```json
{"Icao_addr":2837120,"OnGround":false,"Lat":42.193336,"Lng":-83.92136,"Position_valid":true,"Alt":3400,"Track":9,"Speed":92,"Speed_valid":true,"Vvel":0,"Tail":"","Last_seen":"2015-12-22T21:29:22.252914555Z","Last_source":2}
```
* `http://192.168.10.1/calibrateAHRS` - run AHRS sensor calibration routine. Submit a blank POST to this URL.
* `http://192.168.10.1/cageAHRS` - "level" attitude display. Submit a blank POST to this URL.
* `http://192.168.10.1/resetGMeter` - reset G-meter to zero. Submit a blank POST to this URL.
* `http://192.168.10.1/restart` - restart Stratux application.
* `http://192.168.10.1/reboot` - reboot the system.
* `http://192.168.10.1/shutdown` - shutdown the system.

Wyświetl plik

@ -18,7 +18,6 @@ mkdir -p work/bin
cp gen_gdl90 work/bin/
cp fancontrol work/bin/
cp libdump978.so work/bin/
cp linux-mpu9150/libimu.so work/bin/
cp __lib__systemd__system__stratux.service work/bin/
cp __root__stratux-pre-start.sh work/bin/
cp dump1090/dump1090 work/bin/
@ -39,10 +38,11 @@ cp image/stratux-wifi.sh work/bin/
cp image/rc.local work/bin/
cp image/dhcpd.conf work/bin/
cp image/interfaces work/bin/
cp image/logrotate.conf work/bin
cp test-data/ahrs/ahrs_table.log work/bin/
cp ahrs_approx work/bin/
#TODO: librtlsdr.
cd work/
cat ../selfupdate/update_header.sh >update.sh

Wyświetl plik

@ -1,6 +1,5 @@
cp -f gen_gdl90 /usr/bin/gen_gdl90
cp -f libdump978.so /usr/lib/libdump978.so
cp -f libimu.so /usr/lib/libimu.so
# Startup script.
@ -23,6 +22,9 @@ ln -fs /lib/systemd/system/stratux.service /etc/systemd/system/multi-user.target
cp -f hostapd.conf /etc/hostapd/hostapd.conf
cp -f hostapd-edimax.conf /etc/hostapd/hostapd-edimax.conf
#logrotate config
cp -f logrotate.conf /etc/logrotate.conf
#WiFi Hostapd ver test and hostapd.conf builder script
cp -f stratux-wifi.sh /usr/sbin/

Wyświetl plik

@ -3,5 +3,4 @@
rm -rf /root/stratux-update
mkdir -p /root/stratux-update
cd /root/stratux-update
rm -f /var/log/stratux.sqlite /var/log/stratux.sqlite-wal /var/log/stratux.sqlite-shm
rm -f /var/log/stratux.log
rm -f /var/log/stratux*

Wyświetl plik

@ -1,5 +1,110 @@
<div class="col-sm-12">
<div class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">AHRS</div>
<div class="panel-body">
<div class="col-xs-12">
<span style="position:relative; overflow: hidden;">
<button class="btn btn-primary btn-block" ui-turn-on="modalCalibrateForward"
ng-disabled="!IMU_Sensor_Enabled">Set AHRS Sensor Orientation</button>
</span>
</div>
<div class="form-group reset-flow">
<div class="col-xs-12">
<button class="btn btn-primary btn-block" ui-turn-on="modalCalibrateGyros"
ng-disabled="!IMU_Sensor_Enabled">Calibrate Gyros</button>
</div>
</div>
<div class="form-group reset-flow">
<label class="control-label col-xs-5">G Limits</label>
<form name="GLimitForm" ng-submit="updateGLimits()" novalidate ng-disabled="!IMU_Sensor_Enabled">
<input class="col-xs-7" type="string" required ng-model="GLimits" ng-blur="updateGLimits()"
placeholder="Space-separated negative and positive G meter limits"/>
</form>
</div>
</div>
</div>
</div>
<div class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Configuration</div>
<div class="panel-body">
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Mode S Code (Hex)</label>
<form name="modeForm" ng-submit="updatemodes()" novalidate>
<!-- type="number" not supported except on mobile -->
<!-- RegEx for validation: ^[A-Fa-f0-9]{6}$ -->
<input class="col-xs-7" type="string" required ng-model="OwnshipModeS" placeholder="FAA HEX code" ng-blur="updatemodes()" />
</form>
</div>
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Watch List</label>
<form name="watchForm" ng-submit="updatewatchlist()" novalidate>
<!-- type="number" not supported except on mobile -->
<input class="col-xs-7" type="string" required ng-model="WatchList" placeholder="space-delimited identifiers" ng-blur="updatewatchlist()" />
</form>
</div>
<div ng-show="DeveloperMode" class="form-group reset-flow">
<label class="control-label col-xs-5">PPM Correction</label>
<form name="ppmForm" ng-submit="updateppm()" novalidate>
<!-- type="number" not supported except on mobile -->
<input class="col-xs-7" type="number_format" required ng-model="PPM" placeholder="integer" ng-blur="updateppm()" />
</form>
</div>
<div class="form-group reset-flow" ng-class="{ 'section_invisible': (!visible_serialout)}">
<label class="control-label col-xs-5">Serial Output Baudrate</label>
<form name="ppmForm" ng-submit="updateBaud()" novalidate>
<!-- type="number" not supported except on mobile -->
<input class="col-xs-7" type="number_format" required ng-model="Baud" placeholder="integer" ng-blur="updateBaud()" />
</form>
</div>
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Static IPs</label>
<form name="staticipForm" ng-submit="updatestaticips()" novalidate>
<input class="col-xs-7" type="string" required ng-model="StaticIps" ng-list=" " ng-trim="false" placeholder="space-delimited ip's to send network data" ng-blur="updatestaticips()" />
</form>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-12">
<div class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Commands</div>
<div class="panel-body">
<!-- Upload. Temporary. -->
<div class="col-xs-12">
<span ng-show="update_files == ''">
<span style="position:relative; overflow: hidden;">
<span class="fake-btn fake-btn-block">Click to select System Update file</span>
<input style="opacity:0.0; position: absolute; top: 0; right: 0;" class="col-xs-12" type="file" name="update_file" onchange="angular.element(this).scope().setUploadFile(this.files)"/>
</span>
</span>
<span ng-hide="update_files == ''">
<button class="btn btn-block" onclick="angular.element(this).scope().uploadFile()">Install {{update_files[0].name}}</button>
</span>
</div>
<div class="form-group reset-flow">
<div class="col-xs-12">
<button class="btn btn-primary btn-block" ui-turn-on="modalReboot">Reboot</button>
</div>
</div>
<div class="form-group reset-flow">
<div class="col-xs-12">
<button class="btn btn-primary btn-block"ui-turn-on="modalShutdown">Shutdown</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Developer mode area -->
<div class="col-sm-12">
<div ng-show="DeveloperMode" class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Hardware</div>
<div class="panel-body">
@ -42,8 +147,7 @@
</div>
</div>
</div>
<div class="panel-group col-sm-6">
<div ng-show="DeveloperMode" class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Diagnostics</div>
<div class="panel-body">
@ -75,120 +179,6 @@
</div>
</div>
<div class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">AHRS</div>
<div class="panel-body">
<div class="col-xs-12">
<span style="position:relative; overflow: hidden;">
<button class="btn btn-primary btn-block" ui-turn-on="modalCalibrateForward"
ng-disabled="!IMU_Sensor_Enabled">Set AHRS Sensor Orientation</button>
</span>
</div>
<div class="form-group reset-flow">
<div class="col-xs-12">
<button class="btn btn-primary btn-block" ui-turn-on="modalCalibrateGyros"
ng-disabled="!IMU_Sensor_Enabled">Calibrate Gyros</button>
</div>
</div>
<div class="form-group reset-flow">
<label class="control-label col-xs-5">G Limits</label>
<form name="GLimitForm" ng-submit="updateGLimits()" novalidate ng-disabled="!IMU_Sensor_Enabled">
<input class="col-xs-7" type="string" required ng-model="GLimits" ng-blur="updateGLimits()"
placeholder="Space-separated negative and positive G meter limits"/>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-12">
<div class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Configuration</div>
<div class="panel-body">
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Mode S Code (Hex)</label>
<form name="modeForm" ng-submit="updatemodes()" novalidate>
<!-- type="number" not supported except on mobile -->
<!-- RegEx for validation: ^[A-Fa-f0-9]{6}$ -->
<input class="col-xs-7" type="string" required ng-model="OwnshipModeS" placeholder="FAA HEX code" ng-blur="updatemodes()" />
</form>
</div>
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Watch List</label>
<form name="watchForm" ng-submit="updatewatchlist()" novalidate>
<!-- type="number" not supported except on mobile -->
<input class="col-xs-7" type="string" required ng-model="WatchList" placeholder="space-delimited identifiers" ng-blur="updatewatchlist()" />
</form>
</div>
<div class="form-group reset-flow">
<label class="control-label col-xs-5">PPM Correction</label>
<form name="ppmForm" ng-submit="updateppm()" novalidate>
<!-- type="number" not supported except on mobile -->
<input class="col-xs-7" type="number_format" required ng-model="PPM" placeholder="integer" ng-blur="updateppm()" />
</form>
</div>
<div class="form-group reset-flow" ng-class="{ 'section_invisible': (!visible_serialout)}">
<label class="control-label col-xs-5">Serial Output Baudrate</label>
<form name="ppmForm" ng-submit="updateBaud()" novalidate>
<!-- type="number" not supported except on mobile -->
<input class="col-xs-7" type="number_format" required ng-model="Baud" placeholder="integer" ng-blur="updateBaud()" />
</form>
</div>
</div>
</div>
</div>
<div class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Commands</div>
<div class="panel-body">
<!-- Upload. Temporary. -->
<div class="col-xs-12">
<span ng-show="update_files == ''">
<span style="position:relative; overflow: hidden;">
<span class="fake-btn fake-btn-block">Click to select System Update file</span>
<input style="opacity:0.0; position: absolute; top: 0; right: 0;" class="col-xs-12" type="file" name="update_file" onchange="angular.element(this).scope().setUploadFile(this.files)"/>
</span>
</span>
<span ng-hide="update_files == ''">
<button class="btn btn-block" onclick="angular.element(this).scope().uploadFile()">Install {{update_files[0].name}}</button>
</span>
</div>
<div class="form-group reset-flow">
<div class="col-xs-12">
<button class="btn btn-primary btn-block" ui-turn-on="modalReboot">Reboot</button>
</div>
</div>
<div class="form-group reset-flow">
<div class="col-xs-12">
<button class="btn btn-primary btn-block"ui-turn-on="modalShutdown">Shutdown</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Developer mode area -->
<div class="col-sm-12">
<div ng-show="DeveloperMode" class="panel-group col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">Developer Options</div>
<div class="panel-body">
<div class="col-xs-12">
<div class="form-group reset-flow">
<label class="control-label col-xs-5">Static IPs</label>
<form name="staticipForm" ng-submit="updatestaticips()" novalidate>
<input class="col-xs-7" type="string" required ng-model="StaticIps" ng-list=" " ng-trim="false" placeholder="space-delimited ip's to send network data" ng-blur="updatestaticips()" />
</form>
</div>
</div>
</div>
</div>
</div>
</div>