kopia lustrzana https://github.com/cyoung/stratux
split out fancontrol and gen_gdl90 into different modules, and a common module that shares code between the two
rodzic
f09ae859d1
commit
ee97b68b67
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
|
|
||||||
// Use this to make it possible to hide the gen_gdl90 vs fancontrol redeclaration errors..
|
// Use this to make it possible to hide the gen_gdl90 vs fancontrol redeclaration errors..
|
||||||
//"files.exclude": {
|
"files.exclude": {
|
||||||
// "**/.git": true,
|
"**/.git": true,
|
||||||
// "main/fancontrol.go": true
|
"main/fancontrol.go": true
|
||||||
//}
|
}
|
||||||
}
|
}
|
11
Makefile
11
Makefile
|
@ -24,18 +24,15 @@ else
|
||||||
OGN_RX_BINARY=ogn/ogn-rx-eu_arm
|
OGN_RX_BINARY=ogn/ogn-rx-eu_arm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
STRATUX_SRC=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 main/lowpower_uat.go main/ogn.go main/flarm-nmea.go main/networksettings.go main/xplane.go
|
|
||||||
FANCONTROL_SRC=main/fancontrol.go main/equations.go main/cputemp.go
|
|
||||||
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
make xdump978 xdump1090 gen_gdl90 $(PLATFORMDEPENDENT)
|
make xdump978 xdump1090 gen_gdl90 $(PLATFORMDEPENDENT)
|
||||||
|
|
||||||
gen_gdl90: $(STRATUX_SRC)
|
gen_gdl90: main/*.go common/*.go
|
||||||
export CGO_CFLAGS_ALLOW="-L/root/stratux" && go build $(BUILDINFO) -o gen_gdl90 -p 4 $(STRATUX_SRC)
|
export CGO_CFLAGS_ALLOW="-L/root/stratux" && go build $(BUILDINFO) -o gen_gdl90 -p 4 ./main/
|
||||||
|
|
||||||
fancontrol: $(FANCONTROL_SRC)
|
fancontrol: fancontrol_main/*.go common/*.go
|
||||||
go build $(BUILDINFO) -o fancontrol -p 4 $(FANCONTROL_SRC)
|
go build $(BUILDINFO) -o fancontrol -p 4 ./fancontrol_main/
|
||||||
|
|
||||||
xdump1090:
|
xdump1090:
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
|
|
@ -15,11 +15,9 @@ FANCONTROL_SRC=main/fancontrol.go main/equations.go main/cputemp.go
|
||||||
|
|
||||||
all: xdump978 xdump1090 gen_gdl90 $(PLATFORMDEPENDENT)
|
all: xdump978 xdump1090 gen_gdl90 $(PLATFORMDEPENDENT)
|
||||||
|
|
||||||
gen_gdl90: $(STRATUX_SRC)
|
gen_gdl90: main/*.go common/*.go
|
||||||
CGO_CFLAGS_ALLOW="-L$(CURDIR)" go build $(BUILDINFO) -gcflags '-N -l' -p 4 $(STRATUX_SRC)
|
CGO_CFLAGS_ALLOW="-L$(CURDIR)" go build $(BUILDINFO) -gcflags '-N -l' -o gen_gdl90 -p 4 ./main/
|
||||||
|
|
||||||
fancontrol:
|
|
||||||
go build $(BUILDINFO) -p 4 $(FANCONTROL_SRC)
|
|
||||||
|
|
||||||
xdump1090:
|
xdump1090:
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -7,7 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const invalidCpuTemp = float32(-99.0)
|
const InvalidCpuTemp = float32(-99.0)
|
||||||
|
|
||||||
type CpuTempUpdateFunc func(cpuTemp float32)
|
type CpuTempUpdateFunc func(cpuTemp float32)
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@ calls a callback. This is broken out into its own function (run as
|
||||||
its own goroutine) because the RPi temperature monitor code is buggy,
|
its own goroutine) because the RPi temperature monitor code is buggy,
|
||||||
and often times reading this file hangs quite some time. */
|
and often times reading this file hangs quite some time. */
|
||||||
|
|
||||||
func cpuTempMonitor(updater CpuTempUpdateFunc) {
|
func CpuTempMonitor(updater CpuTempUpdateFunc) {
|
||||||
timer := time.NewTicker(1 * time.Second)
|
timer := time.NewTicker(1 * time.Second)
|
||||||
for {
|
for {
|
||||||
// Update CPUTemp.
|
// Update CPUTemp.
|
||||||
temp, err := ioutil.ReadFile("/sys/class/thermal/thermal_zone0/temp")
|
temp, err := ioutil.ReadFile("/sys/class/thermal/thermal_zone0/temp")
|
||||||
tempStr := strings.Trim(string(temp), "\n")
|
tempStr := strings.Trim(string(temp), "\n")
|
||||||
t := invalidCpuTemp
|
t := InvalidCpuTemp
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tInt, err := strconv.Atoi(tempStr)
|
tInt, err := strconv.Atoi(tempStr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -33,7 +33,7 @@ func cpuTempMonitor(updater CpuTempUpdateFunc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t >= invalidCpuTemp { // Only update if valid value was obtained.
|
if t >= InvalidCpuTemp { // Only update if valid value was obtained.
|
||||||
updater(t)
|
updater(t)
|
||||||
}
|
}
|
||||||
<-timer.C
|
<-timer.C
|
||||||
|
@ -41,6 +41,6 @@ func cpuTempMonitor(updater CpuTempUpdateFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if CPU temperature is valid. Assume <= 0 is invalid.
|
// Check if CPU temperature is valid. Assume <= 0 is invalid.
|
||||||
func isCPUTempValid(cpuTemp float32) bool {
|
func IsCPUTempValid(cpuTemp float32) bool {
|
||||||
return cpuTemp > 0
|
return cpuTemp > 0
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
and other fuctions of Stratux package
|
and other fuctions of Stratux package
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package main
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -18,7 +18,7 @@ import (
|
||||||
// linReg calculates slope and intercept for a least squares linear regression of y[] vs x[]
|
// linReg calculates slope and intercept for a least squares linear regression of y[] vs x[]
|
||||||
// Returns error if fewer than two data points in each series, or if series lengths are different
|
// Returns error if fewer than two data points in each series, or if series lengths are different
|
||||||
|
|
||||||
func linReg(x, y []float64) (slope, intercept float64, valid bool) {
|
func LinReg(x, y []float64) (slope, intercept float64, valid bool) {
|
||||||
|
|
||||||
n := len(x)
|
n := len(x)
|
||||||
nf := float64(n)
|
nf := float64(n)
|
||||||
|
@ -60,7 +60,7 @@ func linReg(x, y []float64) (slope, intercept float64, valid bool) {
|
||||||
// Returns error if fewer than two data points in each series, if series lengths are different,
|
// Returns error if fewer than two data points in each series, if series lengths are different,
|
||||||
// if weights sum to zero, or if slope is infinite
|
// if weights sum to zero, or if slope is infinite
|
||||||
|
|
||||||
func linRegWeighted(x, y, w []float64) (slope, intercept float64, valid bool) {
|
func LinRegWeighted(x, y, w []float64) (slope, intercept float64, valid bool) {
|
||||||
|
|
||||||
n := len(x)
|
n := len(x)
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ func linRegWeighted(x, y, w []float64) (slope, intercept float64, valid bool) {
|
||||||
|
|
||||||
// triCubeWeight returns the value of the tricube weight function
|
// triCubeWeight returns the value of the tricube weight function
|
||||||
// at point x, for the given center and halfwidth.
|
// at point x, for the given center and halfwidth.
|
||||||
func triCubeWeight(center, halfwidth, x float64) float64 {
|
func TriCubeWeight(center, halfwidth, x float64) float64 {
|
||||||
var weight, x_t float64
|
var weight, x_t float64
|
||||||
x_t = math.Abs((x - center) / halfwidth)
|
x_t = math.Abs((x - center) / halfwidth)
|
||||||
if x_t < 1 {
|
if x_t < 1 {
|
||||||
|
@ -124,7 +124,7 @@ func triCubeWeight(center, halfwidth, x float64) float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// arrayMin calculates the minimum value in array x
|
// arrayMin calculates the minimum value in array x
|
||||||
func arrayMin(x []float64) (float64, bool) {
|
func ArrayMin(x []float64) (float64, bool) {
|
||||||
if len(x) < 1 {
|
if len(x) < 1 {
|
||||||
fmt.Printf("arrayMin: Length too short\n")
|
fmt.Printf("arrayMin: Length too short\n")
|
||||||
return math.NaN(), false
|
return math.NaN(), false
|
||||||
|
@ -140,7 +140,7 @@ func arrayMin(x []float64) (float64, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// arrayMax calculates the maximum value in array x
|
// arrayMax calculates the maximum value in array x
|
||||||
func arrayMax(x []float64) (float64, bool) {
|
func ArrayMax(x []float64) (float64, bool) {
|
||||||
if len(x) < 1 {
|
if len(x) < 1 {
|
||||||
fmt.Printf("arrayMax: Length too short\n")
|
fmt.Printf("arrayMax: Length too short\n")
|
||||||
return math.NaN(), false
|
return math.NaN(), false
|
||||||
|
@ -156,9 +156,9 @@ func arrayMax(x []float64) (float64, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// arrayRange calculates the range of values in array x
|
// arrayRange calculates the range of values in array x
|
||||||
func arrayRange(x []float64) (float64, bool) {
|
func ArrayRange(x []float64) (float64, bool) {
|
||||||
max, err1 := arrayMax(x)
|
max, err1 := ArrayMax(x)
|
||||||
min, err2 := arrayMin(x)
|
min, err2 := ArrayMin(x)
|
||||||
|
|
||||||
if !err1 || !err2 {
|
if !err1 || !err2 {
|
||||||
fmt.Printf("Error calculating range\n")
|
fmt.Printf("Error calculating range\n")
|
||||||
|
@ -169,7 +169,7 @@ func arrayRange(x []float64) (float64, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mean returns the arithmetic mean of array x
|
// mean returns the arithmetic mean of array x
|
||||||
func mean(x []float64) (float64, bool) {
|
func Mean(x []float64) (float64, bool) {
|
||||||
if len(x) < 1 {
|
if len(x) < 1 {
|
||||||
fmt.Printf("mean: Length too short\n")
|
fmt.Printf("mean: Length too short\n")
|
||||||
return math.NaN(), false
|
return math.NaN(), false
|
||||||
|
@ -186,14 +186,14 @@ func mean(x []float64) (float64, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// stdev estimates the sample standard deviation of array x
|
// stdev estimates the sample standard deviation of array x
|
||||||
func stdev(x []float64) (float64, bool) {
|
func Stdev(x []float64) (float64, bool) {
|
||||||
if len(x) < 2 {
|
if len(x) < 2 {
|
||||||
fmt.Printf("stdev: Length too short\n")
|
fmt.Printf("stdev: Length too short\n")
|
||||||
return math.NaN(), false
|
return math.NaN(), false
|
||||||
}
|
}
|
||||||
|
|
||||||
nf := float64(len(x))
|
nf := float64(len(x))
|
||||||
xbar, xbarValid := mean(x)
|
xbar, xbarValid := Mean(x)
|
||||||
|
|
||||||
if !xbarValid {
|
if !xbarValid {
|
||||||
fmt.Printf("stdev: Error calculating xbar\n")
|
fmt.Printf("stdev: Error calculating xbar\n")
|
||||||
|
@ -210,17 +210,17 @@ func stdev(x []float64) (float64, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// radians converts angle from degrees, and returns its value in radians
|
// radians converts angle from degrees, and returns its value in radians
|
||||||
func radians(angle float64) float64 {
|
func Radians(angle float64) float64 {
|
||||||
return angle * math.Pi / 180.0
|
return angle * math.Pi / 180.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// degrees converts angle from radians, and returns its value in degrees
|
// degrees converts angle from radians, and returns its value in degrees
|
||||||
func degrees(angle float64) float64 {
|
func Degrees(angle float64) float64 {
|
||||||
return angle * 180.0 / math.Pi
|
return angle * 180.0 / math.Pi
|
||||||
}
|
}
|
||||||
|
|
||||||
// radiansRel converts angle from degrees, and returns its value in radians in the range -Pi to + Pi
|
// radiansRel converts angle from degrees, and returns its value in radians in the range -Pi to + Pi
|
||||||
func radiansRel(angle float64) float64 {
|
func RadiansRel(angle float64) float64 {
|
||||||
for angle > 180 {
|
for angle > 180 {
|
||||||
angle -= 360
|
angle -= 360
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ func radiansRel(angle float64) float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// degreesRel converts angle from radians, and returns its value in the range of -180 to +180 degrees
|
// degreesRel converts angle from radians, and returns its value in the range of -180 to +180 degrees
|
||||||
func degreesRel(angle float64) float64 {
|
func DegreesRel(angle float64) float64 {
|
||||||
for angle > math.Pi {
|
for angle > math.Pi {
|
||||||
angle -= 2 * math.Pi
|
angle -= 2 * math.Pi
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ func degreesRel(angle float64) float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// degreesHdg converts angle from radians, and returns its value in the range of 0+ to 360 degrees
|
// degreesHdg converts angle from radians, and returns its value in the range of 0+ to 360 degrees
|
||||||
func degreesHdg(angle float64) float64 {
|
func DegreesHdg(angle float64) float64 {
|
||||||
for angle < 0 {
|
for angle < 0 {
|
||||||
angle += 2 * math.Pi
|
angle += 2 * math.Pi
|
||||||
}
|
}
|
||||||
|
@ -250,7 +250,7 @@ func degreesHdg(angle float64) float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// roundToInt16 cheaply rounds a float64 to an int16, rather than truncating
|
// roundToInt16 cheaply rounds a float64 to an int16, rather than truncating
|
||||||
func roundToInt16(in float64) (out int16) {
|
func RoundToInt16(in float64) (out int16) {
|
||||||
if in >= 0 {
|
if in >= 0 {
|
||||||
out = int16(in + 0.5)
|
out = int16(in + 0.5)
|
||||||
} else {
|
} else {
|
||||||
|
@ -270,37 +270,37 @@ suitable for relative distance to nearby traffic
|
||||||
// Outputs are distance in meters and bearing in degrees (0° = north, 90° = east)
|
// Outputs are distance in meters and bearing in degrees (0° = north, 90° = east)
|
||||||
// Secondary outputs are north and east components of distance in meters (north, east positive)
|
// Secondary outputs are north and east components of distance in meters (north, east positive)
|
||||||
|
|
||||||
func distRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
|
func DistRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
|
||||||
radius_earth := 6371008.8 // meters; mean radius
|
radius_earth := 6371008.8 // meters; mean radius
|
||||||
dLat := radiansRel(lat2 - lat1)
|
dLat := RadiansRel(lat2 - lat1)
|
||||||
avgLat := radiansRel((lat2 + lat1) / 2)
|
avgLat := RadiansRel((lat2 + lat1) / 2)
|
||||||
dLon := radiansRel(lon2 - lon1)
|
dLon := RadiansRel(lon2 - lon1)
|
||||||
distN = dLat * radius_earth
|
distN = dLat * radius_earth
|
||||||
distE = dLon * radius_earth * math.Abs(math.Cos(avgLat))
|
distE = dLon * radius_earth * math.Abs(math.Cos(avgLat))
|
||||||
dist = math.Pow(distN*distN+distE*distE, 0.5)
|
dist = math.Pow(distN*distN+distE*distE, 0.5)
|
||||||
bearing = math.Atan2(distE, distN)
|
bearing = math.Atan2(distE, distN)
|
||||||
bearing = degreesHdg(bearing)
|
bearing = DegreesHdg(bearing)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// distRectNorth returns north-south distance from point 1 to point 2.
|
// distRectNorth returns north-south distance from point 1 to point 2.
|
||||||
// Inputs are lat in decimal degrees. Output is distance in meters (east positive)
|
// Inputs are lat in decimal degrees. Output is distance in meters (east positive)
|
||||||
func distRectNorth(lat1, lat2 float64) float64 {
|
func DistRectNorth(lat1, lat2 float64) float64 {
|
||||||
var dist float64
|
var dist float64
|
||||||
radius_earth := 6371008.8 // meters; mean radius
|
radius_earth := 6371008.8 // meters; mean radius
|
||||||
dLat := radiansRel(lat2 - lat1)
|
dLat := RadiansRel(lat2 - lat1)
|
||||||
dist = dLat * radius_earth
|
dist = dLat * radius_earth
|
||||||
return dist
|
return dist
|
||||||
}
|
}
|
||||||
|
|
||||||
// distRectEast returns east-west distance from point 1 to point 2.
|
// distRectEast returns east-west distance from point 1 to point 2.
|
||||||
// Inputs are lat/lon in decimal degrees. Output is distance in meters (north positive)
|
// Inputs are lat/lon in decimal degrees. Output is distance in meters (north positive)
|
||||||
func distRectEast(lat1, lon1, lat2, lon2 float64) float64 {
|
func DistRectEast(lat1, lon1, lat2, lon2 float64) float64 {
|
||||||
var dist float64
|
var dist float64
|
||||||
radius_earth := 6371008.8 // meters; mean radius
|
radius_earth := 6371008.8 // meters; mean radius
|
||||||
//dLat := radiansRel(lat2 - lat1) // unused
|
//dLat := radiansRel(lat2 - lat1) // unused
|
||||||
avgLat := radiansRel((lat2 + lat1) / 2)
|
avgLat := RadiansRel((lat2 + lat1) / 2)
|
||||||
dLon := radiansRel(lon2 - lon1)
|
dLon := RadiansRel(lon2 - lon1)
|
||||||
dist = dLon * radius_earth * math.Abs(math.Cos(avgLat))
|
dist = dLon * radius_earth * math.Abs(math.Cos(avgLat))
|
||||||
return dist
|
return dist
|
||||||
}
|
}
|
||||||
|
@ -313,13 +313,13 @@ More accurate over longer distances
|
||||||
// distance calculates distance between two points using the law of cosines.
|
// distance calculates distance between two points using the law of cosines.
|
||||||
// Inputs are lat / lon of both points in decimal degrees
|
// Inputs are lat / lon of both points in decimal degrees
|
||||||
// Outputs are distance in meters and bearing to the target from origin in degrees (0° = north, 90° = east)
|
// Outputs are distance in meters and bearing to the target from origin in degrees (0° = north, 90° = east)
|
||||||
func distance(lat1, lon1, lat2, lon2 float64) (dist, bearing float64) {
|
func Distance(lat1, lon1, lat2, lon2 float64) (dist, bearing float64) {
|
||||||
radius_earth := 6371008.8 // meters; mean radius
|
radius_earth := 6371008.8 // meters; mean radius
|
||||||
|
|
||||||
lat1 = radians(lat1)
|
lat1 = Radians(lat1)
|
||||||
lon1 = radians(lon1)
|
lon1 = Radians(lon1)
|
||||||
lat2 = radians(lat2)
|
lat2 = Radians(lat2)
|
||||||
lon2 = radians(lon2)
|
lon2 = Radians(lon2)
|
||||||
|
|
||||||
dist = math.Acos(math.Sin(lat1)*math.Sin(lat2)+math.Cos(lat1)*math.Cos(lat2)*math.Cos(lon2-lon1)) * radius_earth
|
dist = math.Acos(math.Sin(lat1)*math.Sin(lat2)+math.Cos(lat1)*math.Cos(lat2)*math.Cos(lon2-lon1)) * radius_earth
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ func distance(lat1, lon1, lat2, lon2 float64) (dist, bearing float64) {
|
||||||
x = math.Cos(lat1)*math.Sin(lat2) - math.Sin(lat1)*math.Cos(lat2)*math.Cos(lon2-lon1)
|
x = math.Cos(lat1)*math.Sin(lat2) - math.Sin(lat1)*math.Cos(lat2)*math.Cos(lon2-lon1)
|
||||||
y = math.Sin(lon2-lon1) * math.Cos(lat2)
|
y = math.Sin(lon2-lon1) * math.Cos(lat2)
|
||||||
|
|
||||||
bearing = degreesHdg(math.Atan2(y, x))
|
bearing = DegreesHdg(math.Atan2(y, x))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -340,14 +340,14 @@ func CalcAltitude(press float64, altoffset int) (altitude float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// golang only defines min/max for float64. Really.
|
// golang only defines min/max for float64. Really.
|
||||||
func iMin(x, y int) int {
|
func IMin(x, y int) int {
|
||||||
if x < y {
|
if x < y {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
|
|
||||||
func iMax(x, y int) int {
|
func IMax(x, y int) int {
|
||||||
if x > y {
|
if x > y {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
|
@ -4,15 +4,17 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
"github.com/takama/daemon"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/b3nn0/stratux/common"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/takama/daemon"
|
||||||
)
|
)
|
||||||
|
|
||||||
// #include <wiringPi.h>
|
// #include <wiringPi.h>
|
||||||
|
@ -121,8 +123,8 @@ func fanControl() {
|
||||||
|
|
||||||
|
|
||||||
myFanControl.TempCurrent = 0
|
myFanControl.TempCurrent = 0
|
||||||
go cpuTempMonitor(func(cpuTemp float32) {
|
go common.CpuTempMonitor(func(cpuTemp float32) {
|
||||||
if isCPUTempValid(cpuTemp) {
|
if common.IsCPUTempValid(cpuTemp) {
|
||||||
myFanControl.TempCurrent = cpuTemp
|
myFanControl.TempCurrent = cpuTemp
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -139,9 +141,9 @@ func fanControl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if myFanControl.TempCurrent > (myFanControl.TempTarget + hysteresis) {
|
if myFanControl.TempCurrent > (myFanControl.TempTarget + hysteresis) {
|
||||||
myFanControl.PWMDutyCurrent = iMax(iMin(myFanControl.PWMDutyMax, myFanControl.PWMDutyCurrent+pwmDutyStep), myFanControl.PWMDutyMin)
|
myFanControl.PWMDutyCurrent = common.IMax(common.IMin(myFanControl.PWMDutyMax, myFanControl.PWMDutyCurrent+pwmDutyStep), myFanControl.PWMDutyMin)
|
||||||
} else if myFanControl.TempCurrent < (myFanControl.TempTarget - hysteresis) {
|
} else if myFanControl.TempCurrent < (myFanControl.TempTarget - hysteresis) {
|
||||||
myFanControl.PWMDutyCurrent = iMax(myFanControl.PWMDutyCurrent-pwmDutyStep, 0)
|
myFanControl.PWMDutyCurrent = common.IMax(myFanControl.PWMDutyCurrent-pwmDutyStep, 0)
|
||||||
if myFanControl.PWMDutyCurrent < myFanControl.PWMDutyMin {
|
if myFanControl.PWMDutyCurrent < myFanControl.PWMDutyMin {
|
||||||
myFanControl.PWMDutyCurrent = myFanControl.PWMDutyMin
|
myFanControl.PWMDutyCurrent = myFanControl.PWMDutyMin
|
||||||
}
|
}
|
|
@ -12,17 +12,19 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"bufio"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/b3nn0/stratux/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -59,7 +61,7 @@ func makeFlarmPFLAUString(ti TrafficInfo) (msg string) {
|
||||||
gpsStatus = 2
|
gpsStatus = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
dist, bearing, _, _ := distRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
dist, bearing, _, _ := common.DistRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
relativeVertical := computeRelativeVertical(ti)
|
relativeVertical := computeRelativeVertical(ti)
|
||||||
alarmLevel := computeAlarmLevel(dist, relativeVertical)
|
alarmLevel := computeAlarmLevel(dist, relativeVertical)
|
||||||
|
|
||||||
|
@ -213,7 +215,7 @@ func makeFlarmPFLAAString(ti TrafficInfo) (msg string, valid bool, alarmLevel ui
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine distance and bearing to target
|
// determine distance and bearing to target
|
||||||
dist, bearing, distN, distE := distRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
dist, bearing, distN, distE := common.DistRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
if !ti.Position_valid {
|
if !ti.Position_valid {
|
||||||
dist = ti.DistanceEstimated
|
dist = ti.DistanceEstimated
|
||||||
distN = ti.DistanceEstimated
|
distN = ti.DistanceEstimated
|
||||||
|
@ -799,11 +801,11 @@ func parseFlarmPFLAA(message []string) {
|
||||||
// lat dist = 60nm = 111,12km
|
// lat dist = 60nm = 111,12km
|
||||||
ti.Lat = mySituation.GPSLatitude + (relNorth / 111120.0)
|
ti.Lat = mySituation.GPSLatitude + (relNorth / 111120.0)
|
||||||
avgLat := ti.Lat / 2.0 + mySituation.GPSLatitude / 2.0
|
avgLat := ti.Lat / 2.0 + mySituation.GPSLatitude / 2.0
|
||||||
lngFactor := float32(111120.0 * math.Cos(radians(float64(avgLat))))
|
lngFactor := float32(111120.0 * math.Cos(common.Radians(float64(avgLat))))
|
||||||
ti.Lng = mySituation.GPSLongitude + (relEast / lngFactor)
|
ti.Lng = mySituation.GPSLongitude + (relEast / lngFactor)
|
||||||
|
|
||||||
if isGPSValid() {
|
if isGPSValid() {
|
||||||
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
ti.Distance, ti.Bearing = common.Distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
ti.BearingDist_valid = true
|
ti.BearingDist_valid = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/b3nn0/stratux/common"
|
||||||
"github.com/b3nn0/stratux/uatparse"
|
"github.com/b3nn0/stratux/uatparse"
|
||||||
humanize "github.com/dustin/go-humanize"
|
humanize "github.com/dustin/go-humanize"
|
||||||
"github.com/ricochet2200/go-disk-usage/du"
|
"github.com/ricochet2200/go-disk-usage/du"
|
||||||
|
@ -552,7 +553,7 @@ func makeStratuxStatus() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid/Enabled: CPU temperature portion.
|
// Valid/Enabled: CPU temperature portion.
|
||||||
if isCPUTempValid(globalStatus.CPUTemp) {
|
if common.IsCPUTempValid(globalStatus.CPUTemp) {
|
||||||
msg[13] = msg[13] | (1 << 4)
|
msg[13] = msg[13] | (1 << 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1726,14 +1727,14 @@ func main() {
|
||||||
go baroAltGuesser()
|
go baroAltGuesser()
|
||||||
|
|
||||||
// Monitor RPi CPU temp.
|
// Monitor RPi CPU temp.
|
||||||
globalStatus.CPUTempMin = invalidCpuTemp
|
globalStatus.CPUTempMin = common.InvalidCpuTemp
|
||||||
globalStatus.CPUTempMax = invalidCpuTemp
|
globalStatus.CPUTempMax = common.InvalidCpuTemp
|
||||||
go cpuTempMonitor(func(cpuTemp float32) {
|
go common.CpuTempMonitor(func(cpuTemp float32) {
|
||||||
globalStatus.CPUTemp = cpuTemp
|
globalStatus.CPUTemp = cpuTemp
|
||||||
if isCPUTempValid(cpuTemp) && ((cpuTemp < globalStatus.CPUTempMin) || !isCPUTempValid(globalStatus.CPUTempMin)) {
|
if common.IsCPUTempValid(cpuTemp) && ((cpuTemp < globalStatus.CPUTempMin) || !common.IsCPUTempValid(globalStatus.CPUTempMin)) {
|
||||||
globalStatus.CPUTempMin = cpuTemp
|
globalStatus.CPUTempMin = cpuTemp
|
||||||
}
|
}
|
||||||
if isCPUTempValid(cpuTemp) && ((cpuTemp > globalStatus.CPUTempMax) || !isCPUTempValid(globalStatus.CPUTempMax)) {
|
if common.IsCPUTempValid(cpuTemp) && ((cpuTemp > globalStatus.CPUTempMax) || !common.IsCPUTempValid(globalStatus.CPUTempMax)) {
|
||||||
globalStatus.CPUTempMax = cpuTemp
|
globalStatus.CPUTempMax = cpuTemp
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
46
main/gps.go
46
main/gps.go
|
@ -10,10 +10,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"errors"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -25,6 +25,8 @@ import (
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/b3nn0/stratux/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -681,7 +683,7 @@ func calcGPSAttitude() bool {
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
tempTime[i] = float64(myGPSPerfStats[i].nmeaTime)
|
tempTime[i] = float64(myGPSPerfStats[i].nmeaTime)
|
||||||
}
|
}
|
||||||
minTime, _ := arrayMin(tempTime)
|
minTime, _ := common.ArrayMin(tempTime)
|
||||||
if minTime > 86401.0 {
|
if minTime > 86401.0 {
|
||||||
log.Printf("GPS attitude: Rebasing GPS time since midnight to current day.\n")
|
log.Printf("GPS attitude: Rebasing GPS time since midnight to current day.\n")
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
|
@ -757,7 +759,7 @@ func calcGPSAttitude() bool {
|
||||||
if myGPSPerfStats[i].msgType == "GPRMC" || myGPSPerfStats[i].msgType == "GNRMC" {
|
if myGPSPerfStats[i].msgType == "GPRMC" || myGPSPerfStats[i].msgType == "GNRMC" {
|
||||||
tempSpeed = append(tempSpeed, float64(myGPSPerfStats[i].gsf))
|
tempSpeed = append(tempSpeed, float64(myGPSPerfStats[i].gsf))
|
||||||
tempSpeedTime = append(tempSpeedTime, float64(myGPSPerfStats[i].nmeaTime))
|
tempSpeedTime = append(tempSpeedTime, float64(myGPSPerfStats[i].nmeaTime))
|
||||||
tempRegWeights = append(tempRegWeights, triCubeWeight(center, halfwidth, float64(myGPSPerfStats[i].nmeaTime)))
|
tempRegWeights = append(tempRegWeights, common.TriCubeWeight(center, halfwidth, float64(myGPSPerfStats[i].nmeaTime)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lengthSpeed = len(tempSpeed)
|
lengthSpeed = len(tempSpeed)
|
||||||
|
@ -767,7 +769,7 @@ func calcGPSAttitude() bool {
|
||||||
} else if lengthSpeed == 1 {
|
} else if lengthSpeed == 1 {
|
||||||
v_x = tempSpeed[0] * 1.687810
|
v_x = tempSpeed[0] * 1.687810
|
||||||
} else {
|
} else {
|
||||||
slope, intercept, valid = linRegWeighted(tempSpeedTime, tempSpeed, tempRegWeights)
|
slope, intercept, valid = common.LinRegWeighted(tempSpeedTime, tempSpeed, tempRegWeights)
|
||||||
if !valid {
|
if !valid {
|
||||||
log.Printf("GPS attitude: Error calculating speed regression from NMEA RMC position messages")
|
log.Printf("GPS attitude: Error calculating speed regression from NMEA RMC position messages")
|
||||||
return false
|
return false
|
||||||
|
@ -786,7 +788,7 @@ func calcGPSAttitude() bool {
|
||||||
if myGPSPerfStats[i].msgType == "GPGGA" || myGPSPerfStats[i].msgType == "GNGGA" {
|
if myGPSPerfStats[i].msgType == "GPGGA" || myGPSPerfStats[i].msgType == "GNGGA" {
|
||||||
tempVV = append(tempVV, float64(myGPSPerfStats[i].alt))
|
tempVV = append(tempVV, float64(myGPSPerfStats[i].alt))
|
||||||
tempSpeedTime = append(tempSpeedTime, float64(myGPSPerfStats[i].nmeaTime))
|
tempSpeedTime = append(tempSpeedTime, float64(myGPSPerfStats[i].nmeaTime))
|
||||||
tempRegWeights = append(tempRegWeights, triCubeWeight(center, halfwidth, float64(myGPSPerfStats[i].nmeaTime)))
|
tempRegWeights = append(tempRegWeights, common.TriCubeWeight(center, halfwidth, float64(myGPSPerfStats[i].nmeaTime)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lengthSpeed = len(tempVV)
|
lengthSpeed = len(tempVV)
|
||||||
|
@ -794,7 +796,7 @@ func calcGPSAttitude() bool {
|
||||||
log.Printf("GPS Attitude: Not enough points to calculate vertical speed from NMEA GGA messages\n")
|
log.Printf("GPS Attitude: Not enough points to calculate vertical speed from NMEA GGA messages\n")
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
slope, _, valid = linRegWeighted(tempSpeedTime, tempVV, tempRegWeights)
|
slope, _, valid = common.LinRegWeighted(tempSpeedTime, tempVV, tempRegWeights)
|
||||||
if !valid {
|
if !valid {
|
||||||
log.Printf("GPS attitude: Error calculating vertical speed regression from NMEA GGA messages")
|
log.Printf("GPS attitude: Error calculating vertical speed regression from NMEA GGA messages")
|
||||||
return false
|
return false
|
||||||
|
@ -846,9 +848,9 @@ func calcGPSAttitude() bool {
|
||||||
|
|
||||||
if lengthHeading > 1 {
|
if lengthHeading > 1 {
|
||||||
tempHdgUnwrapped[0] = tempHdg[0]
|
tempHdgUnwrapped[0] = tempHdg[0]
|
||||||
tempRegWeights[0] = triCubeWeight(center, halfwidth, tempHdgTime[0])
|
tempRegWeights[0] = common.TriCubeWeight(center, halfwidth, tempHdgTime[0])
|
||||||
for i := 1; i < lengthHeading; i++ {
|
for i := 1; i < lengthHeading; i++ {
|
||||||
tempRegWeights[i] = triCubeWeight(center, halfwidth, tempHdgTime[i])
|
tempRegWeights[i] = common.TriCubeWeight(center, halfwidth, tempHdgTime[i])
|
||||||
if math.Abs(tempHdg[i]-tempHdg[i-1]) < 180 { // case 1: if angle change is less than 180 degrees, use the same reference system
|
if math.Abs(tempHdg[i]-tempHdg[i-1]) < 180 { // case 1: if angle change is less than 180 degrees, use the same reference system
|
||||||
tempHdgUnwrapped[i] = tempHdgUnwrapped[i-1] + tempHdg[i] - tempHdg[i-1]
|
tempHdgUnwrapped[i] = tempHdgUnwrapped[i-1] + tempHdg[i] - tempHdg[i-1]
|
||||||
} else if tempHdg[i] > tempHdg[i-1] { // case 2: heading has wrapped around from NE to NW. Subtract 360 to keep consistent with previous data.
|
} else if tempHdg[i] > tempHdg[i-1] { // case 2: heading has wrapped around from NE to NW. Subtract 360 to keep consistent with previous data.
|
||||||
|
@ -865,7 +867,7 @@ func calcGPSAttitude() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, calculate turn rate as the slope of the weighted linear regression of unwrapped heading.
|
// Finally, calculate turn rate as the slope of the weighted linear regression of unwrapped heading.
|
||||||
slope, intercept, valid = linRegWeighted(tempHdgTime, tempHdgUnwrapped, tempRegWeights)
|
slope, intercept, valid = common.LinRegWeighted(tempHdgTime, tempHdgUnwrapped, tempRegWeights)
|
||||||
|
|
||||||
if !valid {
|
if !valid {
|
||||||
log.Printf("GPS attitude: Regression error calculating turn rate")
|
log.Printf("GPS attitude: Regression error calculating turn rate")
|
||||||
|
@ -918,7 +920,7 @@ func calcGPSAttitude() bool {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g := 32.174 // ft/(s^2)
|
g := 32.174 // ft/(s^2)
|
||||||
omega = radians(myGPSPerfStats[index].gpsTurnRate) // need radians/sec
|
omega = common.Radians(myGPSPerfStats[index].gpsTurnRate) // need radians/sec
|
||||||
a_c = v_x * omega
|
a_c = v_x * omega
|
||||||
myGPSPerfStats[index].gpsRoll = math.Atan2(a_c, g) * 180 / math.Pi // output is degrees
|
myGPSPerfStats[index].gpsRoll = math.Atan2(a_c, g) * 180 / math.Pi // output is degrees
|
||||||
myGPSPerfStats[index].gpsLoadFactor = math.Sqrt(a_c*a_c+g*g) / g
|
myGPSPerfStats[index].gpsLoadFactor = math.Sqrt(a_c*a_c+g*g) / g
|
||||||
|
@ -980,7 +982,7 @@ func calculateNavRate() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
var halfwidth float64
|
var halfwidth float64
|
||||||
dt_avg, valid := mean(tempSpeedTime)
|
dt_avg, valid := common.Mean(tempSpeedTime)
|
||||||
if valid && dt_avg > 0 {
|
if valid && dt_avg > 0 {
|
||||||
if globalSettings.DEBUG {
|
if globalSettings.DEBUG {
|
||||||
log.Printf("GPS attitude: Average delta time is %.2f s (%.1f Hz)\n", dt_avg, 1/dt_avg)
|
log.Printf("GPS attitude: Average delta time is %.2f s (%.1f Hz)\n", dt_avg, 1/dt_avg)
|
||||||
|
@ -1755,7 +1757,7 @@ func baroAltGuesser() {
|
||||||
alts = append(alts, float64(k*100))
|
alts = append(alts, float64(k*100))
|
||||||
diffs = append(diffs, float64(v))
|
diffs = append(diffs, float64(v))
|
||||||
}
|
}
|
||||||
slope, intercept, valid := linReg(alts, diffs)
|
slope, intercept, valid := common.LinReg(alts, diffs)
|
||||||
//fmt.Printf("General: %f * x + %f \n", slope, intercept)
|
//fmt.Printf("General: %f * x + %f \n", slope, intercept)
|
||||||
|
|
||||||
trafficMutex.Lock()
|
trafficMutex.Lock()
|
||||||
|
@ -1819,7 +1821,7 @@ func baroAltGuesser() {
|
||||||
// X-axis is altitude, Y axis is reported GnssBaroDiff
|
// X-axis is altitude, Y axis is reported GnssBaroDiff
|
||||||
}
|
}
|
||||||
if len(gnssBaroAltDiffs) >= 2 {
|
if len(gnssBaroAltDiffs) >= 2 {
|
||||||
slope, intercept, valid := linRegWeighted(alts, diffs, weights)
|
slope, intercept, valid := common.LinRegWeighted(alts, diffs, weights)
|
||||||
if valid {
|
if valid {
|
||||||
gnssBaroDiff := float64(myAlt) * slope + intercept
|
gnssBaroDiff := float64(myAlt) * slope + intercept
|
||||||
mySituation.muBaro.Lock()
|
mySituation.muBaro.Lock()
|
||||||
|
@ -1897,10 +1899,10 @@ func makeFFAHRSMessage() {
|
||||||
|
|
||||||
if isAHRSValid() {
|
if isAHRSValid() {
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSPitch) {
|
if !isAHRSInvalidValue(mySituation.AHRSPitch) {
|
||||||
pitch = roundToInt16(mySituation.AHRSPitch * 10)
|
pitch = common.RoundToInt16(mySituation.AHRSPitch * 10)
|
||||||
}
|
}
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSRoll) {
|
if !isAHRSInvalidValue(mySituation.AHRSRoll) {
|
||||||
roll = roundToInt16(mySituation.AHRSRoll * 10)
|
roll = common.RoundToInt16(mySituation.AHRSRoll * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1959,27 +1961,27 @@ func makeAHRSGDL90Report() {
|
||||||
vs := int16(0x7FFF)
|
vs := int16(0x7FFF)
|
||||||
if isAHRSValid() {
|
if isAHRSValid() {
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSPitch) {
|
if !isAHRSInvalidValue(mySituation.AHRSPitch) {
|
||||||
pitch = roundToInt16(mySituation.AHRSPitch * 10)
|
pitch = common.RoundToInt16(mySituation.AHRSPitch * 10)
|
||||||
}
|
}
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSRoll) {
|
if !isAHRSInvalidValue(mySituation.AHRSRoll) {
|
||||||
roll = roundToInt16(mySituation.AHRSRoll * 10)
|
roll = common.RoundToInt16(mySituation.AHRSRoll * 10)
|
||||||
}
|
}
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSGyroHeading) {
|
if !isAHRSInvalidValue(mySituation.AHRSGyroHeading) {
|
||||||
hdg = roundToInt16(mySituation.AHRSGyroHeading * 10)
|
hdg = common.RoundToInt16(mySituation.AHRSGyroHeading * 10)
|
||||||
}
|
}
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSSlipSkid) {
|
if !isAHRSInvalidValue(mySituation.AHRSSlipSkid) {
|
||||||
slip_skid = roundToInt16(-mySituation.AHRSSlipSkid * 10)
|
slip_skid = common.RoundToInt16(-mySituation.AHRSSlipSkid * 10)
|
||||||
}
|
}
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSTurnRate) {
|
if !isAHRSInvalidValue(mySituation.AHRSTurnRate) {
|
||||||
yaw_rate = roundToInt16(mySituation.AHRSTurnRate * 10)
|
yaw_rate = common.RoundToInt16(mySituation.AHRSTurnRate * 10)
|
||||||
}
|
}
|
||||||
if !isAHRSInvalidValue(mySituation.AHRSGLoad) {
|
if !isAHRSInvalidValue(mySituation.AHRSGLoad) {
|
||||||
g = roundToInt16(mySituation.AHRSGLoad * 10)
|
g = common.RoundToInt16(mySituation.AHRSGLoad * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isTempPressValid() {
|
if isTempPressValid() {
|
||||||
palt = uint16(mySituation.BaroPressureAltitude + 5000.5)
|
palt = uint16(mySituation.BaroPressureAltitude + 5000.5)
|
||||||
vs = roundToInt16(float64(mySituation.BaroVerticalSpeed))
|
vs = common.RoundToInt16(float64(mySituation.BaroVerticalSpeed))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roll.
|
// Roll.
|
||||||
|
|
19
main/ogn.go
19
main/ogn.go
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2020 Adrian Batzill
|
Copyright (c) 2020 Adrian Batzill
|
||||||
Distributable under the terms of The "BSD New" License
|
Distributable under the terms of The "BSD New" License
|
||||||
|
@ -11,16 +10,18 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/binary"
|
|
||||||
"net"
|
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"log"
|
|
||||||
"io/ioutil"
|
"github.com/b3nn0/stratux/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// {"sys":"OGN","addr":"395F39","addr_type":3,"acft_type":"1","lat_deg":51.7657533,"lon_deg":-1.1918533,"alt_msl_m":124,"alt_std_m":63,"track_deg":0.0,"speed_mps":0.3,"climb_mps":-0.5,"turn_dps":0.0,"DOP":1.5}
|
// {"sys":"OGN","addr":"395F39","addr_type":3,"acft_type":"1","lat_deg":51.7657533,"lon_deg":-1.1918533,"alt_msl_m":124,"alt_std_m":63,"track_deg":0.0,"speed_mps":0.3,"climb_mps":-0.5,"turn_dps":0.0,"DOP":1.5}
|
||||||
|
@ -211,7 +212,7 @@ func importOgnTrafficMessage(msg OgnMessage, data string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic plausibility check:
|
// Basic plausibility check:
|
||||||
dist, _, _, _ := distRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(msg.Lat_deg), float64(msg.Lon_deg))
|
dist, _, _, _ := common.DistRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(msg.Lat_deg), float64(msg.Lon_deg))
|
||||||
if (isGPSValid() && dist >= 50000) || (msg.Lat_deg == 0 && msg.Lon_deg == 0) {
|
if (isGPSValid() && dist >= 50000) || (msg.Lat_deg == 0 && msg.Lon_deg == 0) {
|
||||||
// more than 50km away? Ignore. Most likely invalid data
|
// more than 50km away? Ignore. Most likely invalid data
|
||||||
return
|
return
|
||||||
|
@ -282,7 +283,7 @@ func importOgnTrafficMessage(msg OgnMessage, data string) {
|
||||||
ti.SignalLevel = msg.SNR_dB
|
ti.SignalLevel = msg.SNR_dB
|
||||||
|
|
||||||
if isGPSValid() {
|
if isGPSValid() {
|
||||||
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
ti.Distance, ti.Bearing = common.Distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
ti.BearingDist_valid = true
|
ti.BearingDist_valid = true
|
||||||
}
|
}
|
||||||
ti.Position_valid = true
|
ti.Position_valid = true
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/b3nn0/goflying/ahrs"
|
"github.com/b3nn0/goflying/ahrs"
|
||||||
"github.com/b3nn0/goflying/ahrsweb"
|
"github.com/b3nn0/goflying/ahrsweb"
|
||||||
|
"github.com/b3nn0/stratux/common"
|
||||||
"github.com/b3nn0/stratux/sensors"
|
"github.com/b3nn0/stratux/sensors"
|
||||||
"github.com/kidoman/embd"
|
"github.com/kidoman/embd"
|
||||||
_ "github.com/kidoman/embd/host/all"
|
_ "github.com/kidoman/embd/host/all"
|
||||||
|
@ -123,7 +124,7 @@ func tempAndPressureSender() {
|
||||||
mySituation.muBaro.Lock()
|
mySituation.muBaro.Lock()
|
||||||
mySituation.BaroLastMeasurementTime = stratuxClock.Time
|
mySituation.BaroLastMeasurementTime = stratuxClock.Time
|
||||||
mySituation.BaroTemperature = float32(temp)
|
mySituation.BaroTemperature = float32(temp)
|
||||||
altitude = CalcAltitude(press, globalSettings.AltitudeOffset)
|
altitude = common.CalcAltitude(press, globalSettings.AltitudeOffset)
|
||||||
mySituation.BaroPressureAltitude = float32(altitude)
|
mySituation.BaroPressureAltitude = float32(altitude)
|
||||||
if altLast < -2000 {
|
if altLast < -2000 {
|
||||||
altLast = altitude // Initialize
|
altLast = altitude // Initialize
|
||||||
|
|
|
@ -21,6 +21,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/b3nn0/stratux/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-0b2b48fe3aef1f88621a0856110a31c01105c4e6c4e6c40a9a820300000000000000;rs=7;
|
//-0b2b48fe3aef1f88621a0856110a31c01105c4e6c4e6c40a9a820300000000000000;rs=7;
|
||||||
|
@ -86,14 +88,14 @@ type TrafficInfo struct {
|
||||||
SignalLevel float64 // Signal level, dB RSSI.
|
SignalLevel float64 // Signal level, dB RSSI.
|
||||||
Squawk int // Squawk code
|
Squawk int // Squawk code
|
||||||
Position_valid bool //TODO: set when position report received. Unset after n seconds?
|
Position_valid bool //TODO: set when position report received. Unset after n seconds?
|
||||||
Lat float32 // decimal degrees, north positive
|
Lat float32 // decimal common.Degrees, north positive
|
||||||
Lng float32 // decimal degrees, east positive
|
Lng float32 // decimal common.Degrees, east positive
|
||||||
Alt int32 // Pressure altitude, feet
|
Alt int32 // Pressure altitude, feet
|
||||||
GnssDiffFromBaroAlt int32 // GNSS altitude above WGS84 datum. Reported in TC 20-22 messages
|
GnssDiffFromBaroAlt int32 // GNSS altitude above WGS84 datum. Reported in TC 20-22 messages
|
||||||
AltIsGNSS bool // Pressure alt = 0; GNSS alt = 1
|
AltIsGNSS bool // Pressure alt = 0; GNSS alt = 1
|
||||||
NIC int // Navigation Integrity Category.
|
NIC int // Navigation Integrity Category.
|
||||||
NACp int // Navigation Accuracy Category for Position.
|
NACp int // Navigation Accuracy Category for Position.
|
||||||
Track float32 // degrees true
|
Track float32 // common.Degrees true
|
||||||
TurnRate float32 // Turn rate in deg/sec (negative = turning left, positive = right)
|
TurnRate float32 // Turn rate in deg/sec (negative = turning left, positive = right)
|
||||||
Speed uint16 // knots
|
Speed uint16 // knots
|
||||||
Speed_valid bool // set when speed report received.
|
Speed_valid bool // set when speed report received.
|
||||||
|
@ -120,7 +122,7 @@ type TrafficInfo struct {
|
||||||
Alt_fix int32 // Last real, non-extrapolated altitude
|
Alt_fix int32 // Last real, non-extrapolated altitude
|
||||||
|
|
||||||
BearingDist_valid bool // set when bearing and distance information is valid
|
BearingDist_valid bool // set when bearing and distance information is valid
|
||||||
Bearing float64 // Bearing in degrees true to traffic from ownship, if it can be calculated. Units: degrees.
|
Bearing float64 // Bearing in common.Degrees true to traffic from ownship, if it can be calculated. Units: common.Degrees.
|
||||||
Distance float64 // Distance to traffic from ownship, if it can be calculated. Units: meters.
|
Distance float64 // Distance to traffic from ownship, if it can be calculated. Units: meters.
|
||||||
DistanceEstimated float64 // Estimated distance of the target if real distance can't be calculated, Estimated from signal strength with exponential smoothing.
|
DistanceEstimated float64 // Estimated distance of the target if real distance can't be calculated, Estimated from signal strength with exponential smoothing.
|
||||||
DistanceEstimatedLastTs time.Time // Used to compute moving average
|
DistanceEstimatedLastTs time.Time // Used to compute moving average
|
||||||
|
@ -225,7 +227,7 @@ func isOwnshipTrafficInfo(ti TrafficInfo) (isOwnshipInfo bool, shouldIgnore bool
|
||||||
}
|
}
|
||||||
trafficDist := 0.0
|
trafficDist := 0.0
|
||||||
if isGPSValid() {
|
if isGPSValid() {
|
||||||
trafficDist, _, _, _ = distRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
trafficDist, _, _, _ = common.DistRect(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
}
|
}
|
||||||
altDiff := 99999.0
|
altDiff := 99999.0
|
||||||
if ti.AltIsGNSS && ti.Alt != 0 {
|
if ti.AltIsGNSS && ti.Alt != 0 {
|
||||||
|
@ -306,7 +308,7 @@ func sendTrafficUpdates() {
|
||||||
for key, ti := range traffic { // ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering.
|
for key, ti := range traffic { // ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering.
|
||||||
if isGPSValid() && ti.Position_valid {
|
if isGPSValid() && ti.Position_valid {
|
||||||
// func distRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
|
// func distRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
|
||||||
dist, bearing := distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
dist, bearing := common.Distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
ti.Distance = dist
|
ti.Distance = dist
|
||||||
ti.Bearing = bearing
|
ti.Bearing = bearing
|
||||||
ti.BearingDist_valid = true
|
ti.BearingDist_valid = true
|
||||||
|
@ -477,17 +479,17 @@ func estimateDistance(ti *TrafficInfo) {
|
||||||
|
|
||||||
// calculates coordinates of a point defined by a location, a bearing, and a distance, thanks to 0x74-0x62
|
// calculates coordinates of a point defined by a location, a bearing, and a distance, thanks to 0x74-0x62
|
||||||
func calcLocationForBearingDistance(lat1, lon1, bearingDeg, distanceNm float64) (lat2, lon2 float64) {
|
func calcLocationForBearingDistance(lat1, lon1, bearingDeg, distanceNm float64) (lat2, lon2 float64) {
|
||||||
lat1Rad := radians(lat1)
|
lat1Rad := common.Radians(lat1)
|
||||||
lon1Rad := radians(lon1)
|
lon1Rad := common.Radians(lon1)
|
||||||
bearingRad := radians(bearingDeg)
|
bearingRad := common.Radians(bearingDeg)
|
||||||
distanceRad := distanceNm / (180 * 60 / math.Pi)
|
distanceRad := distanceNm / (180 * 60 / math.Pi)
|
||||||
|
|
||||||
lat2Rad := math.Asin(math.Sin(lat1Rad)*math.Cos(distanceRad) + math.Cos(lat1Rad)*math.Sin(distanceRad)*math.Cos(bearingRad))
|
lat2Rad := math.Asin(math.Sin(lat1Rad)*math.Cos(distanceRad) + math.Cos(lat1Rad)*math.Sin(distanceRad)*math.Cos(bearingRad))
|
||||||
distanceLon := -math.Atan2(math.Sin(bearingRad)*math.Sin(distanceRad)*math.Cos(lat1Rad), math.Cos(distanceRad)-math.Sin(lat1Rad)*math.Sin(lat2Rad))
|
distanceLon := -math.Atan2(math.Sin(bearingRad)*math.Sin(distanceRad)*math.Cos(lat1Rad), math.Cos(distanceRad)-math.Sin(lat1Rad)*math.Sin(lat2Rad))
|
||||||
lon2Rad := math.Mod(lon1Rad-distanceLon+math.Pi, 2.0*math.Pi) - math.Pi
|
lon2Rad := math.Mod(lon1Rad-distanceLon+math.Pi, 2.0*math.Pi) - math.Pi
|
||||||
|
|
||||||
lat2 = degrees(lat2Rad)
|
lat2 = common.Degrees(lat2Rad)
|
||||||
lon2 = degrees(lon2Rad)
|
lon2 = common.Degrees(lon2Rad)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -639,7 +641,7 @@ func makeTrafficReportMsg(ti TrafficInfo) []byte {
|
||||||
msg[16] = byte(vvel & 0x00FF)
|
msg[16] = byte(vvel & 0x00FF)
|
||||||
|
|
||||||
// Track.
|
// Track.
|
||||||
trk := uint8(ti.Track / TRACK_RESOLUTION) // Resolution is ~1.4 degrees.
|
trk := uint8(ti.Track / TRACK_RESOLUTION) // Resolution is ~1.4 common.Degrees.
|
||||||
msg[17] = byte(trk)
|
msg[17] = byte(trk)
|
||||||
|
|
||||||
msg[18] = ti.Emitter_category
|
msg[18] = ti.Emitter_category
|
||||||
|
@ -871,7 +873,7 @@ func parseDownlinkReport(s string, signalLevel int) {
|
||||||
ti.Lat = lat
|
ti.Lat = lat
|
||||||
ti.Lng = lng
|
ti.Lng = lng
|
||||||
if isGPSValid() {
|
if isGPSValid() {
|
||||||
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
ti.Distance, ti.Bearing = common.Distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
}
|
}
|
||||||
ti.Last_seen = stratuxClock.Time
|
ti.Last_seen = stratuxClock.Time
|
||||||
ti.ExtrapolatedPosition = false
|
ti.ExtrapolatedPosition = false
|
||||||
|
@ -1172,7 +1174,7 @@ func esListen() {
|
||||||
ti.Lat = lat
|
ti.Lat = lat
|
||||||
ti.Lng = lng
|
ti.Lng = lng
|
||||||
if isGPSValid() {
|
if isGPSValid() {
|
||||||
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
ti.Distance, ti.Bearing = common.Distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||||
ti.BearingDist_valid = true
|
ti.BearingDist_valid = true
|
||||||
}
|
}
|
||||||
ti.Position_valid = true
|
ti.Position_valid = true
|
||||||
|
@ -1467,7 +1469,7 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
|
||||||
ti.Lat = float32(lat + traffRelLat)
|
ti.Lat = float32(lat + traffRelLat)
|
||||||
ti.Lng = float32(lng + traffRelLng)
|
ti.Lng = float32(lng + traffRelLng)
|
||||||
|
|
||||||
ti.Distance, ti.Bearing = distance(float64(lat), float64(lng), float64(ti.Lat), float64(ti.Lng))
|
ti.Distance, ti.Bearing = common.Distance(float64(lat), float64(lng), float64(ti.Lat), float64(ti.Lng))
|
||||||
ti.BearingDist_valid = true
|
ti.BearingDist_valid = true
|
||||||
|
|
||||||
ti.Position_valid = true
|
ti.Position_valid = true
|
||||||
|
|
Ładowanie…
Reference in New Issue