kopia lustrzana https://github.com/cyoung/stratux
commit
3f6828a600
|
@ -3,3 +3,9 @@ dump978/uat2esnt
|
|||
dump978/uat2json
|
||||
dump978/uat2text
|
||||
gen_gdl90
|
||||
|
||||
*.mp4
|
||||
|
||||
*.img
|
||||
|
||||
*.zip
|
||||
|
|
|
@ -10,8 +10,15 @@ Supported WiFi adapters:
|
|||
* TP-LINK TL-WN725N
|
||||
|
||||
Tested RTL-SDR:
|
||||
*NooElec NESDR Mini 2
|
||||
* NooElec NESDR Mini 2
|
||||
* Generic R820T (degraded performance)
|
||||
|
||||
Tested weather/traffic displays:
|
||||
* ForeFlight 7.2 (Jul 13, 2015) - weather, traffic, AHRS.
|
||||
* Naviator - weather, traffic, AHRS.
|
||||
* WingX - weather & traffic.
|
||||
* Avare
|
||||
* iFly 740 - weather & traffic.
|
||||
|
||||
|
||||
https://www.reddit.com/r/stratux
|
30
gen_gdl90.go
30
gen_gdl90.go
|
@ -15,7 +15,7 @@ import (
|
|||
// http://www.faa.gov/nextgen/programs/adsb/wsa/media/GDL90_Public_ICD_RevA.PDF
|
||||
|
||||
const (
|
||||
stratuxVersion = "v0.1"
|
||||
stratuxVersion = "v0.2"
|
||||
configLocation = "/etc/stratux.conf"
|
||||
managementAddr = "127.0.0.1:9110"
|
||||
maxDatagramSize = 8192
|
||||
|
@ -56,6 +56,7 @@ type msg struct {
|
|||
}
|
||||
|
||||
var MsgLog []msg
|
||||
var timeStarted time.Time
|
||||
|
||||
// Construct the CRC table. Adapted from FAA ref above.
|
||||
func crcInit() {
|
||||
|
@ -299,9 +300,20 @@ func updateStatus() {
|
|||
globalStatus.UAT_messages_last_minute = UAT_messages_last_minute
|
||||
globalStatus.ES_messages_last_minute = ES_messages_last_minute
|
||||
|
||||
// Update "max messages/min" counters.
|
||||
if globalStatus.UAT_messages_max < UAT_messages_last_minute {
|
||||
globalStatus.UAT_messages_max = UAT_messages_last_minute
|
||||
}
|
||||
if globalStatus.ES_messages_max < ES_messages_last_minute {
|
||||
globalStatus.ES_messages_max = ES_messages_last_minute
|
||||
}
|
||||
|
||||
if isGPSValid() {
|
||||
globalStatus.GPS_satellites_locked = mySituation.satellites
|
||||
}
|
||||
|
||||
// Update Uptime.
|
||||
globalStatus.Uptime = time.Since(timeStarted).String()
|
||||
}
|
||||
|
||||
func parseInput(buf string) ([]byte, uint16) {
|
||||
|
@ -372,6 +384,7 @@ type status struct {
|
|||
GPS_satellites_locked uint16
|
||||
GPS_connected bool
|
||||
RY835AI_connected bool
|
||||
Uptime string
|
||||
}
|
||||
|
||||
var globalSettings settings
|
||||
|
@ -427,11 +440,11 @@ func managementInterface() {
|
|||
}
|
||||
|
||||
func defaultSettings() {
|
||||
globalSettings.UAT_Enabled = true //TODO
|
||||
globalSettings.ES_Enabled = true //TODO
|
||||
globalSettings.GPS_Enabled = true //TODO
|
||||
globalSettings.NetworkOutputs = []networkConnection{{nil, "", 4000, NETWORK_GDL90}, {nil, "", 43211, NETWORK_GDL90}, {nil, "", 49002, NETWORK_AHRS}}
|
||||
globalSettings.AHRS_Enabled = true
|
||||
globalSettings.UAT_Enabled = true //TODO
|
||||
globalSettings.ES_Enabled = false //TODO
|
||||
globalSettings.GPS_Enabled = false //TODO
|
||||
globalSettings.NetworkOutputs = []networkConnection{{nil, "", 4000, NETWORK_GDL90_STANDARD}, {nil, "", 43211, NETWORK_GDL90_STANDARD | NETWORK_AHRS_GDL90}, {nil, "", 49002, NETWORK_AHRS_FFSIM}}
|
||||
globalSettings.AHRS_Enabled = false
|
||||
}
|
||||
|
||||
func readSettings() {
|
||||
|
@ -473,6 +486,7 @@ func saveSettings() {
|
|||
}
|
||||
|
||||
func main() {
|
||||
timeStarted = time.Now()
|
||||
runtime.GOMAXPROCS(runtime.NumCPU()) // redundant with Go v1.5+ compiler
|
||||
MsgLog = make([]msg, 0)
|
||||
|
||||
|
@ -480,9 +494,7 @@ func main() {
|
|||
initTraffic()
|
||||
|
||||
globalStatus.Version = stratuxVersion
|
||||
globalStatus.Devices = 123 //TODO
|
||||
globalStatus.UAT_messages_last_minute = 567 //TODO
|
||||
globalStatus.ES_messages_last_minute = 981 //TODO
|
||||
globalStatus.Devices = 0 //TODO
|
||||
|
||||
readSettings()
|
||||
|
||||
|
|
23
network.go
23
network.go
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/inotify"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
|
@ -29,8 +28,9 @@ var dhcpLeases map[string]string
|
|||
var netMutex *sync.Mutex
|
||||
|
||||
const (
|
||||
NETWORK_GDL90 = 1
|
||||
NETWORK_AHRS = 2
|
||||
NETWORK_GDL90_STANDARD = 1
|
||||
NETWORK_AHRS_FFSIM = 2
|
||||
NETWORK_AHRS_GDL90 = 4
|
||||
dhcp_lease_file = "/var/lib/dhcp/dhcpd.leases"
|
||||
)
|
||||
|
||||
|
@ -134,25 +134,16 @@ func sendMsg(msg []byte, msgType uint8) {
|
|||
}
|
||||
|
||||
func sendGDL90(msg []byte) {
|
||||
sendMsg(msg, NETWORK_GDL90)
|
||||
sendMsg(msg, NETWORK_GDL90_STANDARD)
|
||||
}
|
||||
|
||||
func monitorDHCPLeases() {
|
||||
watcher, err := inotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = watcher.AddWatch(dhcp_lease_file, inotify.IN_CLOSE_WRITE)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
//TODO: inotify or dhcp event hook.
|
||||
timer := time.NewTicker(30 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-watcher.Event:
|
||||
log.Println("file modified, attempting to refresh DHCP")
|
||||
case <-timer.C:
|
||||
refreshConnectedClients()
|
||||
case err := <-watcher.Error:
|
||||
log.Println("error with DHCP file system watcher:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
51
ry835ai.go
51
ry835ai.go
|
@ -259,6 +259,53 @@ func tempAndPressureReader() {
|
|||
globalStatus.RY835AI_connected = false
|
||||
}
|
||||
|
||||
func makeFFAHRSSimReport() {
|
||||
s := fmt.Sprintf("XATTStratux,%f,%f,%f", mySituation.gyro_heading, mySituation.pitch, mySituation.roll)
|
||||
|
||||
sendMsg([]byte(s), NETWORK_AHRS_FFSIM)
|
||||
}
|
||||
|
||||
func makeAHRSGDL90Report() {
|
||||
msg := make([]byte, 16)
|
||||
msg[0] = 0x4c
|
||||
msg[1] = 0x45
|
||||
msg[2] = 0x01
|
||||
msg[3] = 0x00
|
||||
|
||||
pitch := int16(float64(mySituation.pitch) * float64(10.0))
|
||||
roll := int16(float64(mySituation.roll) * float64(10.0))
|
||||
hdg := uint16(float64(mySituation.gyro_heading) * float64(10.0)) //TODO.
|
||||
slip_skid := int16(float64(0) * float64(10.0)) //TODO.
|
||||
yaw_rate := int16(float64(0) * float64(10.0)) //TODO.
|
||||
g := int16(float64(1.0) * float64(10.0)) //TODO.
|
||||
|
||||
// Roll.
|
||||
msg[4] = byte((roll >> 8) & 0xFF)
|
||||
msg[5] = byte(roll & 0xFF)
|
||||
|
||||
// Pitch.
|
||||
msg[6] = byte((pitch >> 8) & 0xFF)
|
||||
msg[7] = byte(pitch & 0xFF)
|
||||
|
||||
// Heading.
|
||||
msg[8] = byte((hdg >> 8) & 0xFF)
|
||||
msg[9] = byte(hdg & 0xFF)
|
||||
|
||||
// Slip/skid.
|
||||
msg[10] = byte((slip_skid >> 8) & 0xFF)
|
||||
msg[11] = byte(slip_skid & 0xFF)
|
||||
|
||||
// Yaw rate.
|
||||
msg[12] = byte((yaw_rate >> 8) & 0xFF)
|
||||
msg[13] = byte(yaw_rate & 0xFF)
|
||||
|
||||
// "G".
|
||||
msg[14] = byte((g >> 8) & 0xFF)
|
||||
msg[15] = byte(g & 0xFF)
|
||||
|
||||
sendMsg(prepareMessage(msg), NETWORK_AHRS_GDL90)
|
||||
}
|
||||
|
||||
func attitudeReaderSender() {
|
||||
timer := time.NewTicker(100 * time.Millisecond) // ~10Hz update.
|
||||
for globalStatus.RY835AI_connected && globalSettings.AHRS_Enabled {
|
||||
|
@ -281,9 +328,9 @@ func attitudeReaderSender() {
|
|||
|
||||
// Send, if valid.
|
||||
// if isGPSGroundTrackValid(), etc.
|
||||
s := fmt.Sprintf("XATTStratux,%f,%f,%f", mySituation.gyro_heading, mySituation.pitch, mySituation.roll)
|
||||
|
||||
sendMsg([]byte(s), NETWORK_AHRS)
|
||||
makeFFAHRSSimReport()
|
||||
makeAHRSGDL90Report()
|
||||
|
||||
mySituation.mu_Attitude.Unlock()
|
||||
}
|
||||
|
|
|
@ -360,6 +360,15 @@ func esListen() {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Log the message after we've determined that it at least meets some requirements on the fields.
|
||||
var thisMsg msg
|
||||
thisMsg.MessageClass = MSGCLASS_ES
|
||||
thisMsg.TimeReceived = time.Now()
|
||||
thisMsg.Data = []byte(buf)
|
||||
MsgLog = append(MsgLog, thisMsg)
|
||||
|
||||
// Begin to parse the message.
|
||||
icaoDec := uint32(icaoDecf)
|
||||
trafficMutex.Lock()
|
||||
// Retrieve previous information on this ICAO code.
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
function _str_send($sock, $str) {
|
||||
return socket_send($sock, $str, strlen($str), 0);
|
||||
}
|
||||
|
||||
function get_json($tp) {
|
||||
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (!socket_connect($sock, '127.0.0.1', '9110')) {
|
||||
throw new Exception("couldn't connect");
|
||||
}
|
||||
|
||||
_str_send($sock, $tp);
|
||||
|
||||
$buf = "";
|
||||
socket_recv($sock, $buf, 1024, 0);
|
||||
|
||||
$x = json_decode($buf, true);
|
||||
|
||||
socket_close($sock);
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
function get_settings() {
|
||||
return get_json("SETTINGS\n");
|
||||
}
|
||||
|
||||
function get_status() {
|
||||
return get_json("STATUS\n");
|
||||
}
|
||||
|
||||
function set_settings($to_set) {
|
||||
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (!socket_connect($sock, '127.0.0.1', '9110')) {
|
||||
print "couldn't connect\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$buf = json_encode($to_set);
|
||||
_str_send($sock, $buf . "\n");
|
||||
_str_send($sock, "QUIT\n");
|
||||
}
|
||||
|
||||
$current_settings = get_settings();
|
||||
|
||||
// Copy over old settings to the new ones, such that if there is a field that doesn't change it gets sent over again.
|
||||
if (isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'POST')) {
|
||||
$new_settings = $current_settings;
|
||||
foreach ($_POST as $k => $v) {
|
||||
if ($v === "true") $v = true;
|
||||
else if ($v === "false") $v = false;
|
||||
$new_settings[$k] = $v; //FIXME.
|
||||
}
|
||||
set_settings($new_settings);
|
||||
$current_settings = get_settings();
|
||||
}
|
||||
|
||||
$current_status = get_status();
|
||||
|
||||
$p = array_merge($current_settings, $current_status);
|
||||
|
||||
print json_encode($p) . "\n";
|
||||
?>
|
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Stratux
|
||||
</title>
|
||||
<script src="js/jquery-2.1.4.min.js" type="text/javascript"></script>
|
||||
<script src="js/jquery.form.min.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('input[name=UAT_Enabled]').change(function(){
|
||||
$('#settings').ajaxSubmit({url: 'control.php', type: 'post'})
|
||||
});
|
||||
$('input[name=ES_Enabled]').change(function(){
|
||||
$('#settings').ajaxSubmit({url: 'control.php', type: 'post'})
|
||||
});
|
||||
$('input[name=GPS_Enabled]').change(function(){
|
||||
$('#settings').ajaxSubmit({url: 'control.php', type: 'post'})
|
||||
});
|
||||
$('input[name=AHRS_Enabled]').change(function(){
|
||||
$('#settings').ajaxSubmit({url: 'control.php', type: 'post'})
|
||||
});
|
||||
});
|
||||
(function worker() {
|
||||
$.ajax({
|
||||
url: 'control.php',
|
||||
success: function(data) {
|
||||
obj = $.parseJSON(data);
|
||||
$.each(obj, function(k, v) {
|
||||
// Radio values.
|
||||
if ((k == "UAT_Enabled") || (k == "ES_Enabled") || (k == "GPS_Enabled") || (k == "AHRS_Enabled")) {
|
||||
$('[name=' + k + ']').val([v.toString()]);
|
||||
}
|
||||
$('#' + k).text(v);
|
||||
});
|
||||
|
||||
},
|
||||
complete: function() {
|
||||
// Schedule the next request when the current one is complete.
|
||||
setTimeout(worker, 1000);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
</script>
|
||||
Status:<br>
|
||||
RTL-SDR devices: <span id="Devices">1</span><br>
|
||||
Clients connected: <span id="Connected_Users">2</span><br>
|
||||
Current firmware: <span id="Version">v0.1</span><br>
|
||||
UAT msgs: <span id="UAT_messages_last_minute"></span> / <span id="UAT_messages_max"></span><br>
|
||||
1090ES msgs: <span id="ES_messages_last_minute"></span> / <span id="ES_messages_max"></span><br>
|
||||
GPS satellites: <span id="GPS_satellites_locked"></span><br>
|
||||
AHRS: <span id="RY835AI_connected"></span><br>
|
||||
Uptime: <span id="Uptime"></span><br>
|
||||
<br>
|
||||
<form id="settings">
|
||||
Set:<br>
|
||||
978MHz <input type="radio" name="UAT_Enabled" value="true">On
|
||||
<input type="radio" name="UAT_Enabled" value="false">Off<br>
|
||||
1090MHz <input type="radio" name="ES_Enabled" value="true">On
|
||||
<input type="radio" name="ES_Enabled" value="false">Off<br>
|
||||
GPS <input type="radio" name="GPS_Enabled" value="true">On
|
||||
<input type="radio" name="GPS_Enabled" value="false">Off<br>
|
||||
AHRS <input type="radio" name="AHRS_Enabled" value="true">On
|
||||
<input type="radio" name="AHRS_Enabled" value="false">Off<br>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Ładowanie…
Reference in New Issue