Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into ahrs_dev
Browse files Browse the repository at this point in the history
# Conflicts:
#	Makefile
#	main/equations.go
#	main/gen_gdl90.go
  • Loading branch information
cyoung committed May 13, 2017
2 parents a6f9aaf + d242233 commit c6e96b5
Show file tree
Hide file tree
Showing 11 changed files with 293 additions and 143 deletions.
19 changes: 14 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@

ifeq "$(CIRCLECI)" "true"
BUILDINFO=
PLATFORMDEPENDENT=
else
BUILDINFO=-ldflags "-X main.stratuxVersion=`git describe --tags --abbrev=0` -X main.stratuxBuild=`git log -n 1 --pretty=%H`"
$(if $(GOROOT),,$(error GOROOT is not set!))
PLATFORMDEPENDENT=fancontrol
endif

all:
make xdump978
make xdump1090
make xgen_gdl90
make xdump978 xdump1090 xgen_gdl90 $(PLATFORMDEPENDENT)

xgen_gdl90:
go get -t -d -v ./main ./test ./godump978 ./uatparse ./sensors
go get -u github.com/westphae/goflying/ahrs
go get -u github.com/westphae/goflying/ahrsweb
go build $(BUILDINFO) -p 4 main/gen_gdl90.go main/traffic.go main/gps.go main/network.go main/managementinterface.go main/sdr.go main/ping.go main/uibroadcast.go main/monotonic.go main/datalog.go main/equations.go main/sensors.go
go build $(BUILDINFO) -p 4 main/gen_gdl90.go main/traffic.go main/gps.go main/network.go main/managementinterface.go main/sdr.go main/ping.go main/uibroadcast.go main/monotonic.go main/datalog.go main/equations.go main/sensors.go main/cputemp.go

fancontrol:
go get -t -d -v ./main
go build $(BUILDINFO) -p 4 main/fancontrol.go main/equations.go main/cputemp.go

xdump1090:
git submodule update --init
Expand All @@ -35,6 +39,10 @@ www:
install:
cp -f gen_gdl90 /usr/bin/gen_gdl90
chmod 755 /usr/bin/gen_gdl90
cp -f fancontrol /usr/bin/fancontrol
chmod 755 /usr/bin/fancontrol
-/usr/bin/fancontrol remove
/usr/bin/fancontrol install
cp image/10-stratux.rules /etc/udev/rules.d/10-stratux.rules
cp image/99-uavionix.rules /etc/udev/rules.d/99-uavionix.rules
rm -f /etc/init.d/stratux
Expand All @@ -44,11 +52,12 @@ install:
chmod 744 /root/stratux-pre-start.sh
ln -fs /lib/systemd/system/stratux.service /etc/systemd/system/multi-user.target.wants/stratux.service
make www
cp -f libdump978.so /usr/lib/libdump978.so
cp -f dump1090/dump1090 /usr/bin/
cp -f image/hostapd_manager.sh /usr/sbin/
cp -f image/stratux-wifi.sh /usr/sbin/

clean:
rm -f gen_gdl90 libdump978.so
rm -f gen_gdl90 libdump978.so fancontrol
cd dump1090 && make clean
cd dump978 && make clean
45 changes: 0 additions & 45 deletions image/fancontrol.py

This file was deleted.

12 changes: 10 additions & 2 deletions image/mkimg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,14 @@ chmod 755 mnt/usr/sbin/sdr-tool.sh
cp -f 99-uavionix.rules mnt/etc/udev/rules.d

#fan/temp control script
cp fancontrol.py mnt/usr/bin/
chmod 755 mnt/usr/bin/fancontrol.py
#remove old script
rm -rf mnt/usr/bin/fancontrol.py
#install new program
cp ../fancontrol mnt/usr/bin
chmod 755 mnt/usr/bin/fancontrol
chroot mnt/ /usr/bin/fancontrol remove
chroot mnt/ /usr/bin/fancontrol install


#isc-dhcp-server config
cp -f isc-dhcp-server mnt/etc/default/isc-dhcp-server
Expand Down Expand Up @@ -156,3 +162,5 @@ chroot mnt/ systemctl disable dhcpcd
#disable hciuart - interferes with ttyAMA0 as a serial port.
chroot mnt/ systemctl disable hciuart

#clean up for release images.
rm -rf mnt/root/stratux mnt/root/go
3 changes: 0 additions & 3 deletions image/rc.local
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi


/usr/bin/fancontrol.py start
/usr/bin/stratux-screen.py start


exit 0
48 changes: 48 additions & 0 deletions main/cputemp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"io/ioutil"
"strconv"
"strings"
"time"
)

const invalidCpuTemp = float32(-99.0)

type CpuTempUpdateFunc func(cpuTemp float32)

/* cpuTempMonitor() reads the RPi board temperature every second and
calls a callback. This is broken out into its own function (run as
its own goroutine) because the RPi temperature monitor code is buggy,
and often times reading this file hangs quite some time. */

func cpuTempMonitor(updater CpuTempUpdateFunc) {
timer := time.NewTicker(1 * time.Second)
for {
<-timer.C

// Update CPUTemp.
temp, err := ioutil.ReadFile("/sys/class/thermal/thermal_zone0/temp")
tempStr := strings.Trim(string(temp), "\n")
t := invalidCpuTemp
if err == nil {
tInt, err := strconv.Atoi(tempStr)
if err == nil {
if tInt > 1000 {
t = float32(tInt) / float32(1000.0)
} else {
t = float32(tInt) // case where Temp is returned as simple integer
}
}
}
if t >= invalidCpuTemp { // Only update if valid value was obtained.
updater(t)
}

}
}

// Check if CPU temperature is valid. Assume <= 0 is invalid.
func isCPUTempValid(cpuTemp float32) bool {
return cpuTemp > 0
}
15 changes: 15 additions & 0 deletions main/equations.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,18 @@ func CalcAltitude(press float64) (altitude float64) {
altitude = 145366.45 * (1.0 - math.Pow(press/1013.25, 0.190284))
return
}

// golang only defines min/max for float64. Really.
func iMin(x, y int) int {
if x < y {
return x
}
return y
}

func iMax(x, y int) int {
if x > y {
return x
}
return y
}
190 changes: 190 additions & 0 deletions main/fancontrol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package main

import (
"flag"
"fmt"
"github.com/takama/daemon"
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
)

// #include <wiringPi.h>
// #cgo LDFLAGS: -lwiringPi
import "C"

const (
// CPU temperature target, degrees C
defaultTempTarget = 50.
hysteresis = float32(1.)

/* This puts our PWM frequency at 19.2 MHz / 128 =
/* 150kHz. Higher frequencies will reduce audible switching
/* noise but will be less efficient */
pwmClockDivisor = 128

/* Minimum duty cycle is the point below which the fan does
/* not spin. This depends on both your fan and the switching
/* transistor used. */
defaultPwmDutyMin = 20
pwmDutyMax = 256

// how often to update
delaySeconds = 2

// GPIO-1/BCM "18"/Pin 12 on a Raspberry PI 3
defaultPin = 1

// name of the service
name = "fancontrol"
description = "cooling fan speed control based on CPU temperature"

// port which daemon should be listen
port = ":9977"
)

var stdlog, errlog *log.Logger

func fanControl(pwmDutyMin int, pin int, tempTarget float32) {
cPin := C.int(pin)
C.wiringPiSetup()
C.pwmSetMode(C.PWM_MODE_BAL)
C.pinMode(cPin, C.PWM_OUTPUT)
C.pwmSetRange(pwmDutyMax)
C.pwmSetClock(pwmClockDivisor)
C.pwmWrite(cPin, C.int(pwmDutyMin))
temp := float32(0.)
go cpuTempMonitor(func(cpuTemp float32) {
if isCPUTempValid(cpuTemp) {
temp = cpuTemp
}
})
pwmDuty := 0
for {
if temp > (tempTarget + hysteresis) {
pwmDuty = iMax(iMin(pwmDutyMax, pwmDuty+1), pwmDutyMin)
} else if temp < (tempTarget - hysteresis) {
pwmDuty = iMax(pwmDuty-1, 0)
if pwmDuty < pwmDutyMin {
pwmDuty = 0
}
}
//log.Println(temp, " ", pwmDuty)
C.pwmWrite(cPin, C.int(pwmDuty))
time.Sleep(delaySeconds * time.Second)
}
}

// Service has embedded daemon
type Service struct {
daemon.Daemon
}

// Manage by daemon commands or run the daemon
func (service *Service) Manage() (string, error) {

tempTarget := flag.Float64("temp", defaultTempTarget, "Target CPU Temperature, degrees C")
pwmDutyMin := flag.Int("minduty", defaultPwmDutyMin, "Minimum PWM duty cycle")
pin := flag.Int("pin", defaultPin, "PWM pin (wiringPi numbering)")
flag.Parse()

usage := "Usage: " + name + " install | remove | start | stop | status"
// if received any kind of command, do it
if flag.NArg() > 0 {
command := os.Args[flag.NFlag()+1]
switch command {
case "install":
return service.Install()
case "remove":
return service.Remove()
case "start":
return service.Start()
case "stop":
return service.Stop()
case "status":
return service.Status()
default:
return usage, nil
}
}

go fanControl(*pwmDutyMin, *pin, float32(*tempTarget))

// Set up channel on which to send signal notifications.
// We must use a buffered channel or risk missing the signal
// if we're not ready to receive when the signal is sent.
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

// Set up listener for defined host and port
listener, err := net.Listen("tcp", port)
if err != nil {
return "Possibly was a problem with the port binding", err
}

// set up channel on which to send accepted connections
listen := make(chan net.Conn, 100)
go acceptConnection(listener, listen)

// loop work cycle with accept connections or interrupt
// by system signal
for {
select {
case conn := <-listen:
go handleClient(conn)
case killSignal := <-interrupt:
stdlog.Println("Got signal:", killSignal)
stdlog.Println("Stoping listening on ", listener.Addr())
listener.Close()
if killSignal == os.Interrupt {
return "Daemon was interrupted by system signal", nil
}
return "Daemon was killed", nil
}
}
}

// Accept a client connection and collect it in a channel
func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
for {
conn, err := listener.Accept()
if err != nil {
continue
}
listen <- conn
}
}

func handleClient(client net.Conn) {
for {
buf := make([]byte, 4096)
numbytes, err := client.Read(buf)
if numbytes == 0 || err != nil {
return
}
client.Write(buf[:numbytes])
}
}

func init() {
stdlog = log.New(os.Stdout, "", 0)
errlog = log.New(os.Stderr, "", 0)
}

func main() {
srv, err := daemon.New(name, description, []string{}...)
if err != nil {
errlog.Println("Error: ", err)
os.Exit(1)
}
service := &Service{srv}
status, err := service.Manage()
if err != nil {
errlog.Println(status, "\nError: ", err)
os.Exit(1)
}
fmt.Println(status)
}

0 comments on commit c6e96b5

Please sign in to comment.