Merge remote-tracking branch 'refs/remotes/origin/master' into newradio

pull/750/head
cyoung 2018-06-11 16:48:42 -04:00
commit 8082df9752
12 zmienionych plików z 147 dodań i 4703 usunięć

Wyświetl plik

@ -11,7 +11,7 @@ $(if $(GOROOT),,$(error GOROOT is not set!))
endif
all:
make ahrs_approx xdump978 xdump1090 xgen_gdl90 $(PLATFORMDEPENDENT)
make xdump978 xdump1090 xgen_gdl90 $(PLATFORMDEPENDENT)
xgen_gdl90:
go get -t -d -v ./main ./godump978 ./uatparse ./sensors
@ -29,9 +29,6 @@ xdump978:
cd dump978 && make lib
sudo cp -f ./libdump978.so /usr/lib/libdump978.so
ahrs_approx:
go build $(BUILDINFO) -p 4 test-data/ahrs/ahrs_approx.go
.PHONY: test
test:
make -C test

Wyświetl plik

@ -14,6 +14,7 @@ Raspberry Pi 2 with the Edimax EW-7811Un Wi-Fi dongle is supported but not recom
Tested and works well with most common R820T and R820T2 RTL-SDR devices.
Apps with stratux recognition/support:
* ForeFlight 10+ - weather, traffic, AHRS.
* Seattle Avionics FlyQ EFB 2.1.1+.
* AvNav EFB 2.0.0+.
* Naviator.
@ -24,8 +25,8 @@ Apps with stratux recognition/support:
* iFly GPS 9.4+.
* DroidEFB 2.1.1+.
Tested weather/traffic displays:
* ForeFlight 7+ - weather, traffic. AHRS not functional.
* Avare
Other EFBs? See the [app vendor integration guide](https://github.com/cyoung/stratux/blob/master/notes/app-vendor-integration.md).

Wyświetl plik

@ -2,6 +2,7 @@
dtparam=audio=on
max_usb_current=1
dtparam=i2c_arm=on
dtparam=i2c1=on
dtparam=i2c1_baudrate=400000
dtparam=i2c_arm_baudrate=400000

Wyświetl plik

@ -22,11 +22,14 @@ chroot mnt/ apt-get install -y hostapd isc-dhcp-server
chroot mnt/ apt-get install -y tcpdump
#wifi startup
chroot mnt/ systemctl enable isc-dhcp-server
#ssh startup
chroot mnt/ systemctl enable ssh
#disable ntpd autostart
chroot mnt/ systemctl disable ntp
#root key
mkdir -p mnt/etc/ssh/authorized_keys
cp -f root mnt/etc/ssh/authorized_keys/root
chown root.root mnt/etc/ssh/authorized_keys/root
chmod 644 mnt/etc/ssh/authorized_keys/root
@ -129,10 +132,10 @@ make
make install
#disable serial console
sed -i /boot/cmdline.txt -e "s/console=ttyAMA0,[0-9]\+ //"
sed -i mnt/boot/cmdline.txt -e "s/console=ttyAMA0,[0-9]\+ //"
#Set the keyboard layout to US.
sed -i /etc/default/keyboard -e "/^XKBLAYOUT/s/\".*\"/\"us\"/"
sed -i mnt/etc/default/keyboard -e "/^XKBLAYOUT/s/\".*\"/\"us\"/"
#boot settings
cp -f config.txt mnt/boot/

Wyświetl plik

@ -26,8 +26,4 @@ fi
/usr/bin/stratux-screen.py start
# Dangerzone.
#route add default gw 10.26.36.1
#screen -d -m -S ahrs_approx /usr/bin/ahrs_approx
exit 0

Wyświetl plik

@ -30,10 +30,13 @@ const (
defaultPwmDutyMin = 1
pwmDutyMax = 10
// Temperature at which we give up attempting active fan speed control and set it to full speed.
failsafeTemp = 65
// how often to update
delaySeconds = 30
// GPIO-1/BCM "18"/Pin 12 on a Raspberry PI 3
// GPIO-1/BCM "18"/Pin 12 on a Raspberry Pi 3
defaultPin = 1
// name of the service
@ -96,6 +99,10 @@ func fanControl() {
//log.Println(myFanControl.TempCurrent, " ", myFanControl.PWMDutyCurrent)
C.pwmWrite(cPin, C.int(myFanControl.PWMDutyCurrent))
<-delay.C
if myFanControl.PWMDutyCurrent == myFanControl.PWMDutyMax && myFanControl.TempCurrent >= failsafeTemp {
// Reached the maximum temperature. We stop using PWM control and set the fan to "on" permanently.
break
}
}
// Default to "ON".

Wyświetl plik

@ -408,14 +408,27 @@ func makeOwnshipReport() bool {
msg[19+i] = tail[i]
}
}
// Create callsign "Stratux".
msg[19] = 0x53
msg[20] = 0x74
msg[21] = 0x72
msg[22] = 0x61
msg[23] = 0x74
msg[24] = 0x75
msg[25] = 0x78
myReg := "Stratux" // Default callsign.
// Use icao2reg() results for ownship tail number, if available.
if len(code) == 3 {
uintIcao := uint32(code[0])<<16 | uint32(code[1])<<8 | uint32(code[2])
regFromIcao, regFromIcaoValid := icao2reg(uintIcao)
if regFromIcaoValid {
// Valid "decoded" registration. Use this for the reg.
myReg = regFromIcao
}
}
// Truncate registration to 8 characters.
if len(myReg) > 8 {
myReg = myReg[:8]
}
// Write the callsign.
for i := 0; i < len(myReg); i++ {
msg[19+i] = myReg[i]
}
sendGDL90(prepareMessage(msg), false)
return true
@ -630,6 +643,39 @@ func makeStratuxHeartbeat() []byte {
return prepareMessage(msg)
}
/*
ForeFlight "ID Message".
Sends device information to ForeFlight.
*/
func makeFFIDMessage() []byte {
msg := make([]byte, 39)
msg[0] = 0x65 // Message type "ForeFlight".
msg[1] = 0 // ID message identifier.
msg[2] = 1 // Message version.
// Serial number. Set to "invalid" for now.
for i := 3; i <= 10; i++ {
msg[i] = 0xFF
}
devShortName := "Stratux" // Temporary. Will be populated in the future with other names.
if len(devShortName) > 8 {
devShortName = devShortName[:8] // 8 chars.
}
copy(msg[11:], devShortName)
devLongName := fmt.Sprintf("%s-%s", stratuxVersion, stratuxBuild)
if len(devLongName) > 16 {
devLongName = devLongName[:16] // 16 chars.
}
copy(msg[19:], devLongName)
msg[38] = 0x01 // Capabilities mask. MSL altitude for Ownship Geometric report.
return prepareMessage(msg)
}
func makeHeartbeat() []byte {
msg := make([]byte, 7)
// See p.10.
@ -714,6 +760,7 @@ func heartBeatSender() {
sendGDL90(makeHeartbeat(), false)
sendGDL90(makeStratuxHeartbeat(), false)
sendGDL90(makeStratuxStatus(), false)
sendGDL90(makeFFIDMessage(), false)
makeOwnshipReport()
makeOwnshipGeometricAltitudeReport()

Wyświetl plik

@ -1849,6 +1849,71 @@ func makeFFAHRSSimReport() {
sendMsg([]byte(s), NETWORK_AHRS_FFSIM, false)
}
/*
ForeFlight "AHRS Message".
Sends AHRS information to ForeFlight.
*/
func makeFFAHRSMessage() {
msg := make([]byte, 12)
msg[0] = 0x65 // Message type "ForeFlight".
msg[1] = 0x01 // AHRS message identifier.
// Values if invalid
pitch := int16(0x7FFF)
roll := int16(0x7FFF)
hdg := uint16(0xFFFF)
ias := uint16(0xFFFF)
tas := uint16(0xFFFF)
if isAHRSValid() {
if !isAHRSInvalidValue(mySituation.AHRSPitch) {
pitch = roundToInt16(mySituation.AHRSPitch * 10)
}
if !isAHRSInvalidValue(mySituation.AHRSRoll) {
roll = roundToInt16(mySituation.AHRSRoll * 10)
}
}
// Roll.
msg[2] = byte((roll >> 8) & 0xFF)
msg[3] = byte(roll & 0xFF)
// Pitch.
msg[4] = byte((pitch >> 8) & 0xFF)
msg[5] = byte(pitch & 0xFF)
// Heading.
msg[6] = byte((hdg >> 8) & 0xFF)
msg[7] = byte(hdg & 0xFF)
// Indicated Airspeed.
msg[8] = byte((ias >> 8) & 0xFF)
msg[9] = byte(ias & 0xFF)
// True Airspeed.
msg[10] = byte((tas >> 8) & 0xFF)
msg[11] = byte(tas & 0xFF)
sendMsg(prepareMessage(msg), NETWORK_AHRS_GDL90, false)
}
/*
ffAttitudeSender()
Send AHRS message in FF format every 200ms.
*/
func ffAttitudeSender() {
ticker := time.NewTicker(200 * time.Millisecond)
for {
<-ticker.C
makeFFAHRSMessage()
}
}
func makeAHRSGDL90Report() {
msg := make([]byte, 24)
msg[0] = 0x4c
@ -1874,10 +1939,8 @@ func makeAHRSGDL90Report() {
if !isAHRSInvalidValue(mySituation.AHRSRoll) {
roll = roundToInt16(mySituation.AHRSRoll * 10)
}
if isAHRSInvalidValue(mySituation.AHRSGyroHeading) {
hdg = roundToInt16(mySituation.AHRSGyroHeading * 10) // TODO westphae: switch to AHRSMagHeading?
} else {
hdg = roundToInt16(float64(mySituation.GPSTrueCourse))
if !isAHRSInvalidValue(mySituation.AHRSGyroHeading) {
hdg = roundToInt16(mySituation.AHRSGyroHeading * 10)
}
if !isAHRSInvalidValue(mySituation.AHRSSlipSkid) {
slip_skid = roundToInt16(-mySituation.AHRSSlipSkid * 10)
@ -2049,6 +2112,7 @@ func pollGPS() {
readyToInitGPS = true //TODO: Implement more robust method (channel control) to kill zombie serial readers
timer := time.NewTicker(4 * time.Second)
go gpsAttitudeSender()
go ffAttitudeSender()
for {
<-timer.C
// GPS enabled, was not connected previously?

Wyświetl plik

@ -381,11 +381,13 @@ func handleSettingsSetRequest(w http.ResponseWriter, r *http.Request) {
func handleShutdownRequest(w http.ResponseWriter, r *http.Request) {
syscall.Sync()
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
gracefulShutdown()
}
func doReboot() {
syscall.Sync()
syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
gracefulShutdown()
}
func handleDeleteLogFile(w http.ResponseWriter, r *http.Request) {

Wyświetl plik

@ -277,9 +277,12 @@ func sensorAttitudeSender() {
roll, pitch, heading = s.RollPitchHeading()
mySituation.AHRSRoll = roll / ahrs.Deg
mySituation.AHRSPitch = pitch / ahrs.Deg
mySituation.AHRSGyroHeading = heading / ahrs.Deg
mySituation.AHRSGyroHeading = heading
if !isAHRSInvalidValue(heading) {
mySituation.AHRSGyroHeading /= ahrs.Deg
}
// TODO westphae: until magnetometer calibration is performed, no mag heading
//TODO westphae: until magnetometer calibration is performed, no mag heading
mySituation.AHRSMagHeading = ahrs.Invalid
mySituation.AHRSSlipSkid = s.SlipSkid()
mySituation.AHRSTurnRate = s.RateOfTurn()

Wyświetl plik

@ -1,203 +0,0 @@
package main
import (
"bufio"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"strconv"
"strings"
"sync"
"time"
)
const (
SITUATION_URL = "http://127.0.0.1/getSituation"
)
type MySituation struct {
AHRSRoll float64
AHRSPitch float64
}
var Location MySituation
var situationMutex *sync.Mutex
func chkErr(err error) {
if err != nil {
fmt.Printf("error: %s\n", err.Error())
os.Exit(1)
}
}
/*
ffMonitor().
Watches for "i-want-to-play-ffm-udp", "i-can-play-ffm-udp", and "i-cannot-play-ffm-udp" UDP messages broadcasted on
port 50113. Tags the client, issues a warning, and disables AHRS GDL90 output.
*/
var ffPlay bool
func ffMonitor() {
addr := net.UDPAddr{Port: 50113, IP: net.ParseIP("0.0.0.0")}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Printf("ffMonitor(): error listening on port 50113: %s\n", err.Error())
return
}
defer conn.Close()
for {
buf := make([]byte, 1024)
n, _, err := conn.ReadFrom(buf)
if err != nil {
fmt.Printf("err: %s\n", err.Error())
return
}
// Got message, check if it's in the correct format.
if n < 3 || buf[0] != 0xFF || buf[1] != 0xFE {
continue
}
s := string(buf[2:n])
s = strings.Replace(s, "\x00", "", -1)
if strings.HasPrefix(s, "i-want-to-play-ffm-udp") || strings.HasPrefix(s, "i-can-play-ffm-udp") {
// Enable AHRS emulation.
ffPlay = true
}
}
}
func situationUpdater() {
situationUpdateTicker := time.NewTicker(100 * time.Millisecond)
for {
<-situationUpdateTicker.C
situationMutex.Lock()
resp, err := http.Get(SITUATION_URL)
if err != nil {
fmt.Printf("HTTP GET error: %s\n", err.Error())
situationMutex.Unlock()
continue
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("HTTP GET body error: %s\n", err.Error())
resp.Body.Close()
situationMutex.Unlock()
continue
}
// fmt.Printf("body: %s\n", string(body))
err = json.Unmarshal(body, &Location)
if err != nil {
fmt.Printf("HTTP JSON unmarshal error: %s\n", err.Error())
}
resp.Body.Close()
situationMutex.Unlock()
}
}
type AHRSData struct {
Roll float64
Pitch float64
Trigger []byte
}
func main() {
situationMutex = &sync.Mutex{}
BROADCAST_IPv4 := net.IPv4(255, 255, 255, 255)
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: BROADCAST_IPv4,
Port: 41504,
})
if err != nil {
fmt.Printf("err conn: %s\n", err.Error())
return
}
ahrsTable := make([]AHRSData, 0)
f, err := os.Open("/root/ahrs_table.log")
if err != nil {
fmt.Printf("error: %s\n", err.Error())
return
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
s := scanner.Text()
x := strings.Split(s, ",")
if len(x) < 3 {
continue
}
buf := make([]byte, 1024)
n, err := hex.Decode(buf, []byte(x[2]))
if err != nil || n == 0 {
fmt.Printf("error parsing '%s'.\n", x[2])
continue
}
roll, err := strconv.ParseFloat(x[0], 64)
if err != nil {
fmt.Printf("error parsing '%s'.\n", x[0])
continue
}
pitch, err := strconv.ParseFloat(x[1], 64)
if err != nil {
fmt.Printf("error parsing '%s'.\n", x[1])
continue
}
newEntry := AHRSData{
Roll: roll,
Pitch: pitch,
Trigger: buf[:n],
}
ahrsTable = append(ahrsTable, newEntry)
}
fmt.Printf("loaded %d size ahrs table.\n", len(ahrsTable))
go situationUpdater()
go ffMonitor()
tm := time.NewTicker(125 * time.Millisecond)
for {
<-tm.C
situationMutex.Lock()
myPitch := Location.AHRSPitch
myRoll := Location.AHRSRoll
situationMutex.Unlock()
mB := make([]byte, 0)
var mV float64
for _, v := range ahrsTable {
roll := v.Roll
pitch := v.Pitch
trigger := v.Trigger
z := ((roll - myRoll) * (roll - myRoll)) + ((pitch - myPitch) * (pitch - myPitch))
if (z < mV) || ((mV - 0.000) < 0.00001) {
mV = z
mB = trigger
}
}
if len(mB) > 0 && ffPlay { // Only send if we have both an AHRS approximation to send and FF was detected.
conn.Write(mB)
}
}
}