kopia lustrzana https://github.com/cyoung/stratux
traffic page complete; includes context sensitive help; does not include trafic fource indication
rodzic
94876edd40
commit
45215e258b
29
Makefile
29
Makefile
|
@ -9,8 +9,37 @@ all:
|
|||
test:
|
||||
sh -c true
|
||||
|
||||
www:
|
||||
mkdir -p /var/www
|
||||
mkdir -p /var/www/css
|
||||
cp web/css/*.css /var/www/css
|
||||
mkdir -p /var/www/js
|
||||
cp web/js/*.js /var/www/js
|
||||
mkdir -p /var/www/img
|
||||
cp web/img/logo*.png /var/www/img
|
||||
cp web/img/screen*.png /var/www/img
|
||||
mkdir -p /var/www/maui
|
||||
mkdir -p /var/www/maui/js
|
||||
cp web/maui/js/angular-ui-router.min.js /var/www/maui/js
|
||||
cp web/maui/js/mobile-angular-ui.min.js /var/www/maui/js
|
||||
cp web/maui/js/angular.min.js /var/www/maui/js
|
||||
cp web/maui/js/mobile-angular-ui.gestures.min.js /var/www/maui/js
|
||||
cp web/maui/js/mobile-angular-ui.core.min.js /var/www/maui/js
|
||||
mkdir -p /var/www/maui/css
|
||||
cp web/maui/css/mobile-angular-ui-hover.min.css /var/www/maui/css
|
||||
cp web/maui/css/mobile-angular-ui-desktop.min.css /var/www/maui/css
|
||||
cp web/maui/css/mobile-angular-ui-base.min.css /var/www/maui/css
|
||||
mkdir -p /var/www/maui/fonts
|
||||
cp web/maui/fonts/fontawesome-webfont.woff /var/www/maui/fonts
|
||||
mkdir -p /var/www/plates
|
||||
cp web/plates/*.html /var/www/plates
|
||||
mkdir -p /var/www/plates/js
|
||||
cp web/plates/js/*.js /var/www/plates/js
|
||||
cp web/index.html /var/www
|
||||
|
||||
install:
|
||||
cp -f gen_gdl90 /usr/bin/gen_gdl90
|
||||
chmod 755 /usr/bin/gen_gdl90
|
||||
|
||||
clean:
|
||||
rm -f gen_gdl90
|
||||
|
|
|
@ -43,6 +43,9 @@ func handleWeatherWS(conn *websocket.Conn) {
|
|||
func handleTrafficWS(conn *websocket.Conn) {
|
||||
trafficMutex.Lock()
|
||||
for _, traf := range traffic {
|
||||
if !traf.Position_valid { // Don't send unless a valid position exists.
|
||||
continue
|
||||
}
|
||||
trafficJSON, _ := json.Marshal(&traf)
|
||||
conn.Write(trafficJSON)
|
||||
}
|
||||
|
|
|
@ -48,6 +48,11 @@ AUXSV:
|
|||
|
||||
*/
|
||||
|
||||
const (
|
||||
TRAFFIC_SOURCE_1090ES = 1
|
||||
TRAFFIC_SOURCE_UAT = 2
|
||||
)
|
||||
|
||||
type TrafficInfo struct {
|
||||
Icao_addr uint32
|
||||
addr_type uint8
|
||||
|
@ -68,7 +73,8 @@ type TrafficInfo struct {
|
|||
|
||||
Tail string
|
||||
|
||||
Last_seen time.Time
|
||||
Last_seen time.Time
|
||||
Last_source uint8
|
||||
}
|
||||
|
||||
var traffic map[uint32]TrafficInfo
|
||||
|
@ -96,7 +102,9 @@ func sendTrafficUpdates() {
|
|||
|
||||
// Send update to attached client.
|
||||
func registerTrafficUpdate(ti TrafficInfo) {
|
||||
trafficUpdate <- ti
|
||||
if ti.Position_valid { // Don't send unless a valid position exists.
|
||||
trafficUpdate <- ti
|
||||
}
|
||||
}
|
||||
|
||||
func makeTrafficReport(ti TrafficInfo) {
|
||||
|
@ -326,6 +334,7 @@ func parseDownlinkReport(s string) {
|
|||
//OK.
|
||||
// fmt.Printf("tisb_site_id %d, utc_coupled %t\n", tisb_site_id, utc_coupled)
|
||||
|
||||
ti.Last_source = TRAFFIC_SOURCE_UAT
|
||||
ti.Last_seen = time.Now()
|
||||
|
||||
// Parse tail number, if available.
|
||||
|
@ -497,6 +506,7 @@ func esListen() {
|
|||
}
|
||||
|
||||
// Update "last seen" (any type of message, as long as the ICAO addr can be parsed).
|
||||
ti.Last_source = TRAFFIC_SOURCE_1090ES
|
||||
ti.Last_seen = time.Now()
|
||||
|
||||
ti.addr_type = 0 //FIXME: ADS-B with ICAO address. Not recognized by ForeFlight.
|
||||
|
|
208
web/css/main.css
208
web/css/main.css
|
@ -1,122 +1,216 @@
|
|||
.help-page {
|
||||
font-size: 0.85em;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
.section_invisible {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ahrs_connected {
|
||||
content:
|
||||
content:
|
||||
}
|
||||
|
||||
.ahrs_disconnected {}
|
||||
|
||||
.separator {
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
margin-bottom: 4px;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.label_adj {
|
||||
margin-left: -6px;
|
||||
margin-right: -6px;
|
||||
}
|
||||
|
||||
.col-padding-shift-right {
|
||||
margin-left: -12px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.col-padding-shift-left {
|
||||
margin-left: 12px;
|
||||
margin-right: -12px;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 44px;
|
||||
text-align: center;
|
||||
line-height: 68px;
|
||||
opacity: 0.8;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border: 3px solid;
|
||||
border-radius: 200px;
|
||||
padding: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.list-simple {
|
||||
padding-left: 12px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* ***************************************************************************
|
||||
everything below this comment represents tweeks to the mobile-angular-uis CSS
|
||||
*************************************************************************** */
|
||||
|
||||
.label_adj {
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
src: url('../maui/fonts/fontawesome-webfont.woff?v=4.4.0') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-left: -6px;
|
||||
margin-right: -6px;
|
||||
}
|
||||
|
||||
.col-xs-1,
|
||||
.col-sm-1,
|
||||
.col-md-1,
|
||||
.col-lg-1,
|
||||
.col-xs-2,
|
||||
.col-sm-2,
|
||||
.col-md-2,
|
||||
.col-lg-2,
|
||||
.col-xs-3,
|
||||
.col-sm-3,
|
||||
.col-md-3,
|
||||
.col-lg-3,
|
||||
.col-xs-4,
|
||||
.col-sm-4,
|
||||
.col-md-4,
|
||||
.col-lg-4,
|
||||
.col-xs-5,
|
||||
.col-sm-5,
|
||||
.col-md-5,
|
||||
.col-lg-5,
|
||||
.col-xs-6,
|
||||
.col-sm-6,
|
||||
.col-md-6,
|
||||
.col-lg-6,
|
||||
.col-xs-7,
|
||||
.col-sm-7,
|
||||
.col-md-7,
|
||||
.col-lg-7,
|
||||
.col-xs-8,
|
||||
.col-sm-8,
|
||||
.col-md-8,
|
||||
.col-lg-8,
|
||||
.col-xs-9,
|
||||
.col-sm-9,
|
||||
.col-md-9,
|
||||
.col-lg-9,
|
||||
.col-xs-10,
|
||||
.col-sm-10,
|
||||
.col-md-10,
|
||||
.col-lg-10,
|
||||
.col-xs-11,
|
||||
.col-sm-11,
|
||||
.col-md-11,
|
||||
.col-lg-11,
|
||||
.col-xs-12,
|
||||
.col-sm-12,
|
||||
.col-md-12,
|
||||
.col-lg-12 {
|
||||
position: relative;
|
||||
min-height: 1px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
input[type="number_format"] {
|
||||
text-align: end;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.sidebar .scrollable-header,
|
||||
.panel-title {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
.app-body,
|
||||
.panel-default,
|
||||
.scrollable-content,
|
||||
.form-group {
|
||||
background-color: #ffffff;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.app-content {
|
||||
margin-top: 4px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.sidebar-header,
|
||||
.app-name {
|
||||
line-height: 50px;
|
||||
color: #000;
|
||||
background-color: #f7f7f7;
|
||||
line-height: 50px;
|
||||
color: #000;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
padding: 4px 4px 4px 4px;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-top-right-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
font-weight: bold;
|
||||
padding: 4px 4px 4px 4px;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-top-right-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.panel-group .panel-heading {
|
||||
border-bottom: inherit;
|
||||
border-bottom: inherit;
|
||||
}
|
||||
|
||||
.panel_label {
|
||||
font-size: 16px;
|
||||
margin-top: 4px;
|
||||
display: inline-block;
|
||||
line-height: 12px;
|
||||
vertical-align: bottom;
|
||||
padding-bottom: 2px;
|
||||
font-size: 16px;
|
||||
margin-top: 4px;
|
||||
display: inline-block;
|
||||
line-height: 12px;
|
||||
vertical-align: bottom;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
padding: 8px 4px 4px 4px;
|
||||
padding: 8px 4px 4px 4px;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
line-height: 28px;
|
||||
margin-bottom: 4px;
|
||||
line-height: 28px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.switch {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 52px;
|
||||
height: 28px;
|
||||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 52px;
|
||||
height: 28px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.switch .switch-handle {
|
||||
width: 26px;
|
||||
height: 28px;
|
||||
width: 26px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.switch.active .switch-handle {
|
||||
border-color: #007aff;
|
||||
-webkit-transform: translate(26px, 0);
|
||||
-ms-transform: translate(26px, 0);
|
||||
-o-transform: translate(26px, 0);
|
||||
transform: translate(26px, 0);
|
||||
border-color: #007aff;
|
||||
-webkit-transform: translate(26px, 0);
|
||||
-ms-transform: translate(26px, 0);
|
||||
-o-transform: translate(26px, 0);
|
||||
transform: translate(26px, 0);
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
color: #333333;
|
||||
background-color: inherit;
|
||||
border: 0px;
|
||||
border-radius: 0px;
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.42857143;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
color: #333333;
|
||||
background-color: inherit;
|
||||
border: 0px;
|
||||
border-radius: 0px;
|
||||
}
|
225
web/index.html
225
web/index.html
|
@ -2,137 +2,138 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Stratux</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimal-ui" />
|
||||
<!-- android -->
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link href="img/logo-android3.png" rel="icon" />
|
||||
<!-- iOS -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<link href="img/logo-apple3.png" rel="apple-touch-icon" />
|
||||
<meta charset="utf-8" />
|
||||
<title>Stratux</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimal-ui" />
|
||||
<!-- android -->
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link href="img/logo-android3.png" rel="icon" />
|
||||
<!-- iOS -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<link href="img/logo-apple3.png" rel="apple-touch-icon" />
|
||||
|
||||
<!-- iPad retina portrait startup image -->
|
||||
<link href="img/screen-1536x2008.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" rel="apple-touch-startup-image">
|
||||
<!-- iPad retina landscape startup image -->
|
||||
<link href="img/screen-1496x2048.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" rel="apple-touch-startup-image">
|
||||
<!-- iPad non-retina portrait startup image -->
|
||||
<link href="img/screen-768x1004.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 1) and (orientation: portrait)" rel="apple-touch-startup-image">
|
||||
<!-- iPad non-retina landscape startup image -->
|
||||
<link href="img/screen-748x1024.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 1) and (orientation: landscape)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 6 Plus portrait startup image -->
|
||||
<link href="img/screen-1242x2148.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 6 Plus landscape startup image -->
|
||||
<link href="img/screen-1182x2208.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 6 startup image -->
|
||||
<link href="img/screen-750x1294.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 5 startup image -->
|
||||
<link href="img/screen-640x1096.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone < 5 retina startup image -->
|
||||
<link href="img/screen-640x920.png" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone < 5 non-retina startup image -->
|
||||
<link href="img/screen-320x460.png" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 1)" rel="apple-touch-startup-image">
|
||||
<!-- iPad retina portrait startup image -->
|
||||
<link href="img/screen-1536x2008.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" rel="apple-touch-startup-image">
|
||||
<!-- iPad retina landscape startup image -->
|
||||
<link href="img/screen-1496x2048.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" rel="apple-touch-startup-image">
|
||||
<!-- iPad non-retina portrait startup image -->
|
||||
<link href="img/screen-768x1004.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 1) and (orientation: portrait)" rel="apple-touch-startup-image">
|
||||
<!-- iPad non-retina landscape startup image -->
|
||||
<link href="img/screen-748x1024.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 1) and (orientation: landscape)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 6 Plus portrait startup image -->
|
||||
<link href="img/screen-1242x2148.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 6 Plus landscape startup image -->
|
||||
<link href="img/screen-1182x2208.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 6 startup image -->
|
||||
<link href="img/screen-750x1294.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone 5 startup image -->
|
||||
<link href="img/screen-640x1096.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone < 5 retina startup image -->
|
||||
<link href="img/screen-640x920.png" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image">
|
||||
<!-- iPhone < 5 non-retina startup image -->
|
||||
<link href="img/screen-320x460.png" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 1)" rel="apple-touch-startup-image">
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="css/addtohomescreen.css">
|
||||
<script src="js/addtohomescreen.min.js"></script>
|
||||
<script>
|
||||
addToHomescreen({
|
||||
displayPace: 480
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" type="text/css" href="css/addtohomescreen.css">
|
||||
<script src="js/addtohomescreen.min.js"></script>
|
||||
<script>
|
||||
addToHomescreen({
|
||||
displayPace: 480
|
||||
});
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="maui/css/mobile-angular-ui-base.css" />
|
||||
<link rel="stylesheet" href="maui/css/mobile-angular-ui-hover.css" />
|
||||
<link rel="stylesheet" href="maui/css/mobile-angular-ui-desktop.css" />
|
||||
<link rel="stylesheet" href="maui/css/mobile-angular-ui-base.min.css" />
|
||||
<link rel="stylesheet" href="maui/css/mobile-angular-ui-hover.min.css" />
|
||||
<link rel="stylesheet" href="maui/css/mobile-angular-ui-desktop.min.css" />
|
||||
|
||||
<link rel="stylesheet" href="css/main.css" />
|
||||
<link rel="stylesheet" href="css/main.css" />
|
||||
|
||||
<script src="maui/js/angular.min.js"></script>
|
||||
<script src="maui/js/angular-ui-router.min.js"></script>
|
||||
<script src="maui/js/mobile-angular-ui.min.js"></script>
|
||||
<script src="maui/js/mobile-angular-ui.gestures.min.js"></script>
|
||||
<script src="maui/js/angular.min.js"></script>
|
||||
<script src="maui/js/angular-ui-router.min.js"></script>
|
||||
<script src="maui/js/mobile-angular-ui.min.js"></script>
|
||||
<script src="maui/js/mobile-angular-ui.gestures.min.js"></script>
|
||||
|
||||
<!-- TODO: combine and minify the following javascript -->
|
||||
<script src="js/main.js"></script>
|
||||
<script src="plates/js/ahrs.js"></script>
|
||||
<script src="plates/js/gps.js"></script>
|
||||
<script src="plates/js/logs.js"></script>
|
||||
<script src="plates/js/settings.js"></script>
|
||||
<script src="plates/js/status.js"></script>
|
||||
<script src="plates/js/traffic.js"></script>
|
||||
<script src="plates/js/weather.js"></script>
|
||||
<!-- TODO: combine and minify the following javascript -->
|
||||
<script src="js/main.js"></script>
|
||||
<script src="plates/js/gps.js"></script>
|
||||
<script src="plates/js/logs.js"></script>
|
||||
<script src="plates/js/settings.js"></script>
|
||||
<script src="plates/js/status.js"></script>
|
||||
<script src="plates/js/traffic.js"></script>
|
||||
<script src="plates/js/weather.js"></script>
|
||||
</head>
|
||||
|
||||
<body ng-app="stratux" ng-controller="MainCtrl" ui-prevent-touchmove-defaults>
|
||||
|
||||
<!-- Define Left (Menu) Sidebar Navigation -->
|
||||
<div ui-track-as-search-param='true' class="sidebar sidebar-left">
|
||||
<div class="scrollable">
|
||||
<h3 class="scrollable-header app-name">Menu</h3>
|
||||
<div class="scrollable-content">
|
||||
<div class="list-group" ui-turn-off='uiSidebarLeft'>
|
||||
<!-- hrefs are redirected by the state engine in main.js -->
|
||||
<a class="list-group-item" href="#/"><i class="fa fa-home"></i> Status <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/weather"><i class="fa fa-cloud"></i> Weather <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/traffic"><i class="fa fa-plane"></i> Traffic <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/gps"><i class="fa fa-globe"></i> GPS <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/ahrs"><i class="fa fa-crosshairs"></i> AHRS <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/logs"><i class="fa fa-file-text-o"></i> Logs <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/settings"><i class="fa fa-gear"></i> Settings <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Define Right (Help) Sidebar -->
|
||||
<div class="sidebar sidebar-right">
|
||||
<div class="scrollable">
|
||||
<h3 class="scrollable-header app-name">Help</h3>
|
||||
<div class="scrollable-content">
|
||||
<div class="list-group" ui-toggle="uiSidebarRight">
|
||||
<div ng-include="helppage"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Define Left (Menu) Sidebar Navigation -->
|
||||
<div ui-track-as-search-param='true' class="sidebar sidebar-left">
|
||||
<div class="scrollable">
|
||||
<h3 class="scrollable-header app-name">Menu</h3>
|
||||
<div class="scrollable-content">
|
||||
<div class="list-group" ui-turn-off='uiSidebarLeft'>
|
||||
<!-- hrefs are redirected by the state engine in main.js -->
|
||||
<a class="list-group-item" href="#/"><i class="fa fa-home"></i> Status <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/weather"><i class="fa fa-cloud"></i> Weather <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/traffic"><i class="fa fa-plane"></i> Traffic <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/gps"><i class="fa fa-globe"></i> GPS/AHRS <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<!--
|
||||
<a class="list-group-item" href="#/ahrs"><i class="fa fa-crosshairs"></i> AHRS <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
-->
|
||||
<a class="list-group-item" href="#/logs"><i class="fa fa-file-text-o"></i> Logs <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
<a class="list-group-item" href="#/settings"><i class="fa fa-gear"></i> Settings <i class="fa fa-chevron-right pull-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Define Right (Help) Sidebar -->
|
||||
<div class="sidebar sidebar-right">
|
||||
<div class="scrollable">
|
||||
<h3 class="scrollable-header app-name">Help</h3>
|
||||
<div class="scrollable-content">
|
||||
<div class="list-group" ui-toggle="uiSidebarRight">
|
||||
<div ng-include="helppage"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="app" ui-swipe-right='Ui.turnOn("uiSidebarLeft")' ui-swipe-left='Ui.turnOff("uiSidebarLeft")'>
|
||||
<div class="app" ui-swipe-right='Ui.turnOn("uiSidebarLeft")' ui-swipe-left='Ui.turnOff("uiSidebarLeft")'>
|
||||
|
||||
<!-- Create Header Navbar with left Menu Button -->
|
||||
<div class="navbar navbar-app navbar-absolute-top">
|
||||
<div class="navbar-brand navbar-brand-center" ui-yield-to="title">
|
||||
<a href="#/">
|
||||
<!-- Create Header Navbar with left Menu Button -->
|
||||
<div class="navbar navbar-app navbar-absolute-top">
|
||||
<div class="navbar-brand navbar-brand-center" ui-yield-to="title">
|
||||
<a href="#/">
|
||||
Stratux
|
||||
</a>
|
||||
</div>
|
||||
<div class="btn-group pull-left">
|
||||
<div ui-toggle="uiSidebarLeft" class="btn sidebar-toggle">
|
||||
<i class="fa fa-bars"></i> Menu
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group pull-right" ui-yield-to="navbarAction">
|
||||
<div ui-toggle="uiSidebarRight" class="btn">
|
||||
<i class="fa fa-info-circle"></i> Help
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group pull-left">
|
||||
<div ui-toggle="uiSidebarLeft" class="btn sidebar-toggle">
|
||||
<i class="fa fa-bars"></i> Menu
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group pull-right" ui-yield-to="navbarAction">
|
||||
<div ui-toggle="uiSidebarRight" class="btn">
|
||||
<i class="fa fa-info-circle"></i> Help
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- App Body -->
|
||||
<div class="app-body">
|
||||
<div class="app-content">
|
||||
<div class="scrollable">
|
||||
<div class="scrollable-content">
|
||||
<div ui-view></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- App Body -->
|
||||
<div class="app-body">
|
||||
<div class="app-content">
|
||||
<div class="scrollable">
|
||||
<div class="scrollable-content">
|
||||
<div ui-view></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -12,67 +12,22 @@ var appControllers = angular.module('appControllers', []);
|
|||
|
||||
|
||||
app.config(function ($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('home', {
|
||||
url: '/',
|
||||
templateUrl: 'plates/status.html',
|
||||
controller: 'StatusCtrl',
|
||||
reloadOnSearch: false
|
||||
})
|
||||
.state('weather', {
|
||||
url: '/weather',
|
||||
templateUrl: 'plates/weather.html',
|
||||
controller: 'WeatherCtrl',
|
||||
reloadOnSearch: false
|
||||
})
|
||||
.state('traffic', {
|
||||
url: '/traffic',
|
||||
templateUrl: 'plates/traffic.html',
|
||||
controller: 'TrafficCtrl',
|
||||
reloadOnSearch: false
|
||||
})
|
||||
.state('gps', {
|
||||
url: '/gps',
|
||||
templateUrl: 'plates/gps.html',
|
||||
controller: 'GPSCtrl',
|
||||
reloadOnSearch: false
|
||||
})
|
||||
.state('ahrs', {
|
||||
url: '/ahrs',
|
||||
templateUrl: 'plates/ahrs.html',
|
||||
controller: 'AHRSCtrl',
|
||||
reloadOnSearch: false
|
||||
})
|
||||
.state('logs', {
|
||||
url: '/logs',
|
||||
templateUrl: 'plates/logs.html',
|
||||
controller: 'LogsCtrl',
|
||||
reloadOnSearch: false
|
||||
})
|
||||
.state('settings', {
|
||||
url: '/settings',
|
||||
templateUrl: 'plates/settings.html',
|
||||
controller: 'SettingsCtrl',
|
||||
reloadOnSearch: false
|
||||
});
|
||||
|
||||
$urlRouterProvider.otherwise('/');
|
||||
$stateProvider
|
||||
.state('home', { url: '/', templateUrl: 'plates/status.html', controller: 'StatusCtrl', reloadOnSearch: false })
|
||||
.state('weather', { url: '/weather', templateUrl: 'plates/weather.html', controller: 'WeatherCtrl', reloadOnSearch: false })
|
||||
.state('traffic', { url: '/traffic', templateUrl: 'plates/traffic.html', controller: 'TrafficCtrl', reloadOnSearch: false })
|
||||
.state('gps', { url: '/gps', templateUrl: 'plates/gps.html', controller: 'GPSCtrl', reloadOnSearch: false })
|
||||
.state('logs', { url: '/logs', templateUrl: 'plates/logs.html', controller: 'LogsCtrl', reloadOnSearch: false })
|
||||
.state('settings', { url: '/settings', templateUrl: 'plates/settings.html',controller: 'SettingsCtrl', reloadOnSearch: false });
|
||||
$urlRouterProvider.otherwise('/');
|
||||
});
|
||||
|
||||
|
||||
app.run(function ($transform) {
|
||||
window.$transform = $transform;
|
||||
window.$transform = $transform;
|
||||
});
|
||||
/*
|
||||
app.config(function ($httpProvider) {
|
||||
// We need to setup some parameters for http requests
|
||||
// These three lines are all you need for CORS support
|
||||
$httpProvider.defaults.useXDomain = true;
|
||||
// $httpProvider.defaults.withCredentials = true;
|
||||
delete $httpProvider.defaults.headers.common['X-Requested-With'];
|
||||
});
|
||||
*/
|
||||
// For this app we have a MainController for whatever and the nindividual controllers for each page
|
||||
|
||||
// For this app we have a MainController for whatever and individual controllers for each page
|
||||
app.controller('MainCtrl', function ($rootScope, $scope) {
|
||||
// any logic global logic
|
||||
// any logic global logic
|
||||
});
|
|
@ -1,13 +0,0 @@
|
|||
<div class="list-group text-center">
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<h2>AHRS Status</h2>
|
||||
</div>
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<div>
|
||||
<i class="fa fa-crosshairs feature-icon text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
this space reserved to display AHRS status
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -4,10 +4,10 @@
|
|||
</div>
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<div>
|
||||
<i class="fa fa-glob feature-icon text-primary"></i>
|
||||
<i class="fa fa-globe feature-icon text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
this space reserved to display GPS status
|
||||
this space reserved to display GPS/AHRS status
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,21 +0,0 @@
|
|||
<div class="scrollable">
|
||||
<div class="scrollable-content">
|
||||
<div class="list-group" ui-toggle="uiSidebarRight">
|
||||
|
||||
<div class="list-group text-center">
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<h2>Help</h2>
|
||||
</div>
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<div>
|
||||
<i class="fa fa-info-circle feature-icon text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
this space reserved to display context sensitive help
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,15 +0,0 @@
|
|||
angular.module('appControllers').controller('AHRSCtrl', AHRSCtrl); // get the main module contollers set
|
||||
AHRSCtrl.$inject = ['$rootScope', '$scope', '$state', '$http']; // Inject my dependencies
|
||||
|
||||
// create our controller function with all necessary logic
|
||||
function AHRSCtrl($rootScope, $scope, $state, $http) {
|
||||
|
||||
/*
|
||||
$state.get('weather').onEnter = function () {
|
||||
};
|
||||
$state.get('weather').onExit = function () {
|
||||
};
|
||||
*/
|
||||
|
||||
// Weather Controller tasks go here
|
||||
};
|
|
@ -49,7 +49,7 @@ function SettingsCtrl($rootScope, $scope, $state, $http) {
|
|||
$scope.AHRS_Enabled = settings.AHRS_Enabled;
|
||||
$scope.DEBUG = settings.DEBUG;
|
||||
$scope.ReplayLog = settings.ReplayLog;
|
||||
$scope.PPM = parseInt(settings.PPM);
|
||||
$scope.PPM = settings.PPM;
|
||||
// $scope.$apply();
|
||||
}, function (response) {
|
||||
$scope.rawSettings = "error setting settings";
|
||||
|
@ -82,9 +82,9 @@ function SettingsCtrl($rootScope, $scope, $state, $http) {
|
|||
|
||||
$scope.updateppm = function() {
|
||||
if (($scope.PPM !== undefined) && ($scope.PPM !== null) && $scope.PPM !== settings["PPM"]) {
|
||||
settings["PPM"] = $scope.PPM;
|
||||
settings["PPM"] = parseInt($scope.PPM);
|
||||
newsettings = {
|
||||
"PPM": $scope.PPM
|
||||
"PPM": parseInt($scope.PPM)
|
||||
};
|
||||
console.log(angular.toJson(newsettings));
|
||||
setSettings(angular.toJson(newsettings));
|
||||
|
|
|
@ -11,8 +11,7 @@ function StatusCtrl($rootScope, $scope, $state, $http) {
|
|||
return; // we are getting called once after clicking away from the status page
|
||||
|
||||
if (($scope.socket === undefined) || ($scope.socket === null)) {
|
||||
// socket = new WebSocket('ws://' + window.location.hostname + '/control');
|
||||
socket = new WebSocket('ws://' + URL_HOST_BASE + '/control');
|
||||
socket = new WebSocket('ws://' + URL_HOST_BASE + '/status');
|
||||
$scope.socket = socket; // store socket in scope for enter/exit usage
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,135 @@
|
|||
angular.module('appControllers').controller('TrafficCtrl', TrafficCtrl); // get the main module contollers set
|
||||
TrafficCtrl.$inject = ['$rootScope', '$scope', '$state', '$http']; // Inject my dependencies
|
||||
TrafficCtrl.$inject = ['$rootScope', '$scope', '$state', '$http', '$interval']; // Inject my dependencies
|
||||
|
||||
// create our controller function with all necessary logic
|
||||
function TrafficCtrl($rootScope, $scope, $state, $http) {
|
||||
function TrafficCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||
|
||||
/*
|
||||
$state.get('weather').onEnter = function () {
|
||||
};
|
||||
$state.get('weather').onExit = function () {
|
||||
};
|
||||
*/
|
||||
$scope.$parent.helppage = 'plates/traffic-help.html';
|
||||
$scope.traffic = [];
|
||||
|
||||
// Weather Controller tasks go here
|
||||
function utcTimeString(epoc) {
|
||||
var time = "";
|
||||
var val;
|
||||
var d = new Date(epoc);
|
||||
val = d.getUTCHours();
|
||||
time += (val < 10 ? "0" + val : "" + val);
|
||||
val = d.getUTCMinutes();
|
||||
time += ":" + (val < 10 ? "0" + val : "" + val);
|
||||
val = d.getUTCSeconds();
|
||||
time += ":" + (val < 10 ? "0" + val : "" + val);
|
||||
time += "Z";
|
||||
return time;
|
||||
}
|
||||
|
||||
function dmsString(val) {
|
||||
return [0 | val,
|
||||
'd ',
|
||||
0 | (val < 0 ? val = -val : val) % 1 * 60,
|
||||
"' ",
|
||||
0 | val * 60 % 1 * 60,
|
||||
'"'].join('');
|
||||
}
|
||||
|
||||
function setAircraft(obj, new_traffic) {
|
||||
new_traffic.icao_int = obj.Icao_addr;
|
||||
new_traffic.icao = obj.Icao_addr.toString(16).toUpperCase();
|
||||
new_traffic.tail = obj.Tail;
|
||||
new_traffic.lat = dmsString(obj.Lat);
|
||||
new_traffic.lon = dmsString(obj.Lng);
|
||||
var n = Math.round(obj.Alt / 100) * 100;
|
||||
new_traffic.alt = n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
new_traffic.heading = Math.round(obj.Track / 10) * 10;
|
||||
new_traffic.speed = Math.round(obj.Speed / 10) * 10;
|
||||
new_traffic.vspeed = Math.round(obj.Vvel / 100) * 100
|
||||
new_traffic.age = Date.parse(obj.Last_seen);
|
||||
new_traffic.time = utcTimeString(new_traffic.age);
|
||||
// return new_aircraft;
|
||||
}
|
||||
|
||||
function connect($scope) {
|
||||
if (($scope === undefined) || ($scope === null))
|
||||
return; // we are getting called once after clicking away from the status page
|
||||
|
||||
if (($scope.socket === undefined) || ($scope.socket === null)) {
|
||||
socket = new WebSocket('ws://' + URL_HOST_BASE + '/traffic');
|
||||
$scope.socket = socket; // store socket in scope for enter/exit usage
|
||||
}
|
||||
|
||||
$scope.ConnectState = "Not Receiving";
|
||||
|
||||
socket.onopen = function (msg) {
|
||||
$scope.ConnectStyle = "label-success";
|
||||
$scope.ConnectState = "Receiving";
|
||||
};
|
||||
|
||||
socket.onclose = function (msg) {
|
||||
$scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Not Receiving";
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
|
||||
socket.onerror = function (msg) {
|
||||
$scope.ConnectStyle = "label-danger";
|
||||
$scope.ConnectState = "Problem";
|
||||
};
|
||||
|
||||
socket.onmessage = function (msg) {
|
||||
console.log('Received traffic update.')
|
||||
|
||||
var aircraft = JSON.parse(msg.data);
|
||||
if (aircraft.Position_valid) {
|
||||
$scope.rawTraffic = msg.data;
|
||||
// we need to use an array so AngularJS can perform sorting; it also means we need to loop to find an aircraft in the traffic set
|
||||
var found = false;
|
||||
for (var i = 0, len = $scope.traffic.length; i < len; i++) {
|
||||
if ($scope.traffic[i].icao_int === aircraft.Icao_addr) {
|
||||
setAircraft(aircraft, $scope.traffic[i]);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
var new_traffic = {};
|
||||
setAircraft(aircraft, new_traffic);
|
||||
$scope.traffic.unshift(new_traffic); // add to start of array
|
||||
}
|
||||
$scope.$apply();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// perform cleanup every 60 seconds
|
||||
var clearStaleTraffic = $interval(function () {
|
||||
// remove stail aircraft = anything more than 180 seconds without and update
|
||||
var dirty = false;
|
||||
var cutoff = Date.now() - (180 * 1000);
|
||||
|
||||
for (var i = len = $scope.traffic.length; i > 0; i--) {
|
||||
if ($scope.traffic[i - 1].age < cutoff) {
|
||||
$scope.traffic.splice(i - 1, 1);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
if (dirty) {
|
||||
$scope.$apply();
|
||||
}
|
||||
}, (1000 * 60), 0, false);
|
||||
|
||||
|
||||
$state.get('traffic').onEnter = function () {
|
||||
// everything gets handled correctly by the controller
|
||||
};
|
||||
|
||||
$state.get('traffic').onExit = function () {
|
||||
// disconnect from the socket
|
||||
if (($scope.socket !== undefined) && ($scope.socket !== null)) {
|
||||
$scope.socket.close();
|
||||
$scope.socket = null;
|
||||
}
|
||||
// stop stale traffic cleanup
|
||||
$interval.cancel(clearStaleTraffic);
|
||||
};
|
||||
|
||||
// Traffic Controller tasks
|
||||
connect($scope); // connect - opens a socket and listens for messages
|
||||
};
|
|
@ -6,7 +6,7 @@
|
|||
<stron>Status</stron> page.</p>
|
||||
|
||||
<p>The <strong>Diagnostics</strong> section helps with debugging and communicating with the Stratux project contributors via GitHub and the reddit subgroup.
|
||||
<ul>
|
||||
<ul class="list-simple">
|
||||
<li>Toggling <strong>Traffic Source</strong> adds text for traffic targets within your navigation application. Traffic received via UAT will display <code>u</code> while traffic received via 1090 will display <code>e</code>.</li>
|
||||
<li>Toggling <strong>Record Logs</strong> enables logging to a series of files for your Stratux device including data recorded for UAT traffic and weather, 1090 traffic, GPS messages, and AHRS messages. The log files are accessible from the <strong>Logs</strong> menu available on the left.</li>
|
||||
</ul>
|
||||
|
|
|
@ -1,83 +1,80 @@
|
|||
<div class="col-sm-12">
|
||||
<div class="panel-group col-sm-6">
|
||||
<div class="panel-group col-sm-6">
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Hardware</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">978MHz</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='UAT_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">1090MHz</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='ES_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">GPS</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='GPS_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">AHRS</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='AHRS_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Hardware</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">978MHz</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='UAT_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">1090MHz</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='ES_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">GPS</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='GPS_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">AHRS</label>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='AHRS_Enabled' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-group col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Diagnostics</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">Traffic Markings</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>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='ReplayLog' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-group col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Diagnostics</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-7">Traffic Markings</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>
|
||||
<div class="col-xs-5">
|
||||
<ui-switch ng-model='ReplayLog' settings-change></ui-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Configuration</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-8">PPM Correction</label>
|
||||
<form name="ppmForm" ng-submit="updateppm()" novalidate>
|
||||
<!-- type="number" not supported except on mobile -->
|
||||
<input class="col-xs-4" type="number_format" required ng-model="PPM" placeholder="integer" />
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Configuration</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-8">PPM Correction</label>
|
||||
<form name="ppmForm" ng-submit="updateppm()" novalidate>
|
||||
<!-- type="number" not supported except on mobile -->
|
||||
<input class="col-xs-4" type="number_format" required ng-model="PPM" placeholder="integer" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
|
||||
<div class="panel panel-default" xui-set="{'settingsAccordion' : 4}">
|
||||
<div class="panel-heading">Raw Configuration</div>
|
||||
<div xui-if="settingsAccordion == 4">
|
||||
<div class="panel-body">
|
||||
<p>stratux.conf:</p>
|
||||
<pre>{{rawSettings}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Raw Configuration</div>
|
||||
<div class="panel-body">
|
||||
<p>stratux.conf:</p>
|
||||
<pre>{{rawSettings}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
<p>The current state of you device is shown at th top - <code>Connected</code> in green or <code>Disconected</code>in red.</p>
|
||||
|
||||
<p>Depending on the hardware you have installed in your Stratux, you will have status for the following:</p>
|
||||
<ul>
|
||||
<li>software defined radio (SDR) dongle tuned to 978Mhz for UAT (universal access transceiver) traffic and weather</li>
|
||||
<li>software defined radio (SDR) dongle tuned to 1090Mhz for ES (extended squitter) traffic</li>
|
||||
<li>RY835AI module providing either GPS or GPS+AHRS data</li>
|
||||
<ul class="list-simple">
|
||||
<li><strong>SDR</strong> (software defined radio) dongle tuned to 978Mhz for UAT (universal access transceiver) traffic and weather</li>
|
||||
<li><strong>SDR</strong> (software defined radio) dongle tuned to 1090Mhz for ES (extended squitter) traffic</li>
|
||||
<li><strong>GPS</strong> the RY835AI module receiving GPS data from satellites</li>
|
||||
<li><strong>AHRS</strong> the RY835AI module generating attitude data from its pressure sensor, gyroscope, accelerometer, and magnetometer.</li>
|
||||
</ul>
|
||||
<p class="text-warning">NOTE: This page only shows devices you have installed and turned on (via the <strong>Settings</strong> page.</p>
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<div class="section text-left help-page">
|
||||
<p>The <strong>Traffic</strong> page provides a list of recent aircraft received. Each time a new aircraft is reported, it is added to the list. Each time a new report is received for an existing aircraft, the list is updated. If a report for an aircraft is not received for 3 minutes (180 seconds), the aircraft is removed from the list.</p>
|
||||
<p>For each aircraft, the list includes the following details:</p>
|
||||
<ul class="list-simple">
|
||||
<li><strong>Flight</strong> - either the aircraft tail number / ATC call sign or the ICAO number. When the ICAO number is used, it is displayed in grey.</li>
|
||||
<li><strong>Speed</strong> - current reported speed in knots</li>
|
||||
<li><strong>Altitude</strong> - current reported altitude and climb/decent rate if when not reporting level flight</li>
|
||||
<li><strong>Heading</strong> - direction of reported flight</li>
|
||||
<li><strong>Location</strong> - the latitude and longitude reported</li>
|
||||
<li><strong>Time</strong> - the last time (UTC) a report was received</li>
|
||||
</ul>
|
||||
<p class="text-warning">NOTE: When this page becomes active (aka it is selected from the menu) it will display any traffic received up to the last 3 minutes (180 seconds). Older traffic will not appear.</p>
|
||||
</div>
|
|
@ -1,13 +1,52 @@
|
|||
<div class="list-group text-center">
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<h2>ADSB Traffic</h2>
|
||||
</div>
|
||||
<div class="list-group-item list-group-item-home">
|
||||
<div>
|
||||
<i class="fa fa-plane feature-icon text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
this space reserved to display traffic data
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="panel_label">Traffic</span> <span class="label" ng-class="ConnectStyle">{{ConnectState}}</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-3"><strong>Flight</strong></span>
|
||||
<span class="col-xs-3 text-right">Speed</span>
|
||||
<span class="col-xs-3 text-right">Altitude</span><span class="col-xs-1 col-padding-shift-right"> </span>
|
||||
<span class="col-xs-2 text-right">Hdg</span>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-2"> </span>
|
||||
<span class="col-xs-7">Location</span>
|
||||
<span class="col-xs-3 text-right">Time</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-repeat="aircraft in traffic | orderBy: -age">
|
||||
<div class="separator"></div>
|
||||
<div class="col-sm-6">
|
||||
<span ng-show="aircraft.tail" class="col-xs-3"><strong>{{aircraft.tail}}</strong></span>
|
||||
<span ng-hide="aircraft.tail" class="col-xs-3 text-muted"><strong>{{aircraft.icao}}</strong></span>
|
||||
|
||||
<span class="col-xs-3 text-right">{{aircraft.speed}}KTS</span>
|
||||
<span class="col-xs-3 text-right">{{aircraft.alt}}</span>
|
||||
<span class="col-xs-1 small col-padding-shift-right text-muted">
|
||||
<span ng-show="aircraft.vspeed">(<span ng-show="aircraft.vspeed > 0">+</span>{{aircraft.vspeed}})</span>
|
||||
</span>
|
||||
<span class="col-xs-2 text-right"><span ng-show="aircraft.heading < 10">0</span><span ng-show="aircraft.heading < 100">0</span>{{aircraft.heading}}°</span>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-2"> </span>
|
||||
<span class="col-xs-7">{{aircraft.lat}} {{aircraft.lon}}</span>
|
||||
<span class="col-xs-3 text-right">{{aircraft.time}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Raw Traffic Data</div>
|
||||
<div class="panel-body">
|
||||
<pre>{{rawTraffic}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
Ładowanie…
Reference in New Issue